Просмотр исходного кода

wayland: Clean up gesture support

The gesture capability is tied to the pointer capability, not touch, and may not always be exposed by the compositor.
Frank Praznik 11 месяцев назад
Родитель
Сommit
6f81c70f67

+ 79 - 49
src/video/wayland/SDL_waylandevents.c

@@ -46,6 +46,8 @@
 #include "primary-selection-unstable-v1-client-protocol.h"
 #include "primary-selection-unstable-v1-client-protocol.h"
 #include "input-timestamps-unstable-v1-client-protocol.h"
 #include "input-timestamps-unstable-v1-client-protocol.h"
 #include "pointer-gestures-unstable-v1-client-protocol.h"
 #include "pointer-gestures-unstable-v1-client-protocol.h"
+#include "cursor-shape-v1-client-protocol.h"
+#include "viewporter-client-protocol.h"
 
 
 #ifdef HAVE_LIBDECOR_H
 #ifdef HAVE_LIBDECOR_H
 #include <libdecor.h>
 #include <libdecor.h>
@@ -67,8 +69,6 @@
 #include <unistd.h>
 #include <unistd.h>
 #include <xkbcommon/xkbcommon-compose.h>
 #include <xkbcommon/xkbcommon-compose.h>
 #include <xkbcommon/xkbcommon.h>
 #include <xkbcommon/xkbcommon.h>
-#include "cursor-shape-v1-client-protocol.h"
-#include "viewporter-client-protocol.h"
 
 
 // Weston uses a ratio of 10 units per scroll tick
 // Weston uses a ratio of 10 units per scroll tick
 #define WAYLAND_WHEEL_AXIS_UNIT 10
 #define WAYLAND_WHEEL_AXIS_UNIT 10
@@ -289,6 +289,71 @@ void Wayland_DisplayInitInputTimestampManager(SDL_VideoData *display)
     }
     }
 }
 }
 
 
+static void handle_pinch_begin(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, struct wl_surface *surface, uint32_t fingers)
+{
+    if (!surface) {
+        return;
+    }
+
+    SDL_WindowData *wind = Wayland_GetWindowDataForOwnedSurface(surface);
+    if (wind) {
+        SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
+        seat->pointer.gesture_focus = wind;
+
+        const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
+        SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, timestamp, wind->sdlwindow, 0.0f);
+    }
+}
+
+static void handle_pinch_update(void *data, 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)
+{
+    SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
+
+    if (seat->pointer.gesture_focus) {
+        const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
+        const float s = (float)wl_fixed_to_double(scale);
+        SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, timestamp, seat->pointer.gesture_focus->sdlwindow, s);
+    }
+}
+
+static void handle_pinch_end(void *data, struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled)
+{
+    SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
+
+    if (seat->pointer.gesture_focus) {
+        const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
+        SDL_SendPinch(SDL_EVENT_PINCH_END, timestamp, seat->pointer.gesture_focus->sdlwindow, 0.0f);
+
+        seat->pointer.gesture_focus = NULL;
+    }
+}
+
+static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener = {
+    handle_pinch_begin,
+    handle_pinch_update,
+    handle_pinch_end
+};
+
+static void Wayland_SeatCreatePointerGestures(SDL_WaylandSeat *seat)
+{
+    if (seat->display->zwp_pointer_gestures) {
+        if (seat->pointer.wl_pointer && !seat->pointer.gesture_pinch) {
+            seat->pointer.gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture(seat->display->zwp_pointer_gestures, seat->pointer.wl_pointer);
+            zwp_pointer_gesture_pinch_v1_set_user_data(seat->pointer.gesture_pinch, seat);
+            zwp_pointer_gesture_pinch_v1_add_listener(seat->pointer.gesture_pinch, &gesture_pinch_listener, seat);
+        }
+    }
+}
+
+void Wayland_DisplayInitPointerGestureManager(SDL_VideoData *display)
+{
+    SDL_WaylandSeat *seat;
+    wl_list_for_each (seat, &display->seat_list, link) {
+        Wayland_SeatCreatePointerGestures(seat);
+    }
+}
+
 static void Wayland_SeatCreateCursorShape(SDL_WaylandSeat *seat)
 static void Wayland_SeatCreateCursorShape(SDL_WaylandSeat *seat)
 {
 {
     if (seat->display->cursor_shape_manager) {
     if (seat->display->cursor_shape_manager) {
@@ -1417,43 +1482,6 @@ static const struct wl_touch_listener touch_listener = {
     touch_handler_orientation // Version 6
     touch_handler_orientation // Version 6
 };
 };
 
 
-void pinch_begin(void *data,
-          struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
-          uint32_t serial,
-          uint32_t time,
-          struct wl_surface *surface,
-          uint32_t fingers)
-{
-    SDL_SendPinch(SDL_EVENT_PINCH_BEGIN, 0, NULL, 0);
-}
-void pinch_update(void *data,
-           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)
-{
-
-    float s = (float)(wl_fixed_to_double(scale));
-    SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, NULL, s);
-}
-
-void pinch_end(void *data,
-        struct zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
-        uint32_t serial,
-        uint32_t time,
-        int32_t cancelled)
-{
-    SDL_SendPinch(SDL_EVENT_PINCH_END, 0, NULL, 0);
-}
-
-static const struct zwp_pointer_gesture_pinch_v1_listener gesture_pinch_listener = {
-    pinch_begin,
-    pinch_update,
-    pinch_end
-};
-
 // Fallback for xkb_keymap_key_get_mods_for_level(), which is only available from 1.0.0, while the SDL minimum is 0.5.0.
 // Fallback for xkb_keymap_key_get_mods_for_level(), which is only available from 1.0.0, while the SDL minimum is 0.5.0.
 #if !SDL_XKBCOMMON_CHECK_VERSION(1, 0, 0)
 #if !SDL_XKBCOMMON_CHECK_VERSION(1, 0, 0)
 static size_t xkb_legacy_get_mods_for_level(SDL_WaylandSeat *seat, xkb_keycode_t key, xkb_layout_index_t layout, xkb_level_index_t level, xkb_mod_mask_t *masks_out, size_t masks_size)
 static size_t xkb_legacy_get_mods_for_level(SDL_WaylandSeat *seat, xkb_keycode_t key, xkb_layout_index_t layout, xkb_level_index_t level, xkb_mod_mask_t *masks_out, size_t masks_size)
@@ -2296,6 +2324,11 @@ static const struct wl_keyboard_listener keyboard_listener = {
 
 
 static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat, bool send_event)
 static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat, bool send_event)
 {
 {
+    // End any active gestures.
+    if (seat->pointer.gesture_focus) {
+        SDL_SendPinch(SDL_EVENT_PINCH_END, 0, seat->pointer.gesture_focus->sdlwindow, 0.0f);
+    }
+
     // Make sure focus is removed from a surface before the pointer is destroyed.
     // Make sure focus is removed from a surface before the pointer is destroyed.
     if (seat->pointer.focus) {
     if (seat->pointer.focus) {
         pointer_handle_leave(seat, seat->pointer.wl_pointer, 0, seat->pointer.focus->surface);
         pointer_handle_leave(seat, seat->pointer.wl_pointer, 0, seat->pointer.focus->surface);
@@ -2319,6 +2352,10 @@ static void Wayland_SeatDestroyPointer(SDL_WaylandSeat *seat, bool send_event)
         zwp_input_timestamps_v1_destroy(seat->pointer.timestamps);
         zwp_input_timestamps_v1_destroy(seat->pointer.timestamps);
     }
     }
 
 
+    if (seat->pointer.gesture_pinch) {
+        zwp_pointer_gesture_pinch_v1_destroy(seat->pointer.gesture_pinch);
+    }
+
     if (seat->pointer.cursor_state.frame_callback) {
     if (seat->pointer.cursor_state.frame_callback) {
         wl_callback_destroy(seat->pointer.cursor_state.frame_callback);
         wl_callback_destroy(seat->pointer.cursor_state.frame_callback);
     }
     }
@@ -2425,10 +2462,6 @@ static void Wayland_SeatDestroyTouch(SDL_WaylandSeat *seat)
         }
         }
     }
     }
 
 
-    if (seat->touch.gesture_pinch) {
-        zwp_pointer_gesture_pinch_v1_destroy(seat->touch.gesture_pinch);
-    }
-
     SDL_zero(seat->touch);
     SDL_zero(seat->touch);
     WAYLAND_wl_list_init(&seat->touch.points);
     WAYLAND_wl_list_init(&seat->touch.points);
 }
 }
@@ -2447,6 +2480,9 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum w
         wl_pointer_set_user_data(seat->pointer.wl_pointer, seat);
         wl_pointer_set_user_data(seat->pointer.wl_pointer, seat);
         wl_pointer_add_listener(seat->pointer.wl_pointer, &pointer_listener, seat);
         wl_pointer_add_listener(seat->pointer.wl_pointer, &pointer_listener, seat);
 
 
+        // Pointer gestures
+        Wayland_SeatCreatePointerGestures(seat);
+
         seat->pointer.sdl_id = SDL_GetNextObjectID();
         seat->pointer.sdl_id = SDL_GetNextObjectID();
 
 
         if (seat->name) {
         if (seat->name) {
@@ -2472,12 +2508,6 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, enum w
         }
         }
 
 
         SDL_AddTouch((SDL_TouchID)(uintptr_t)seat->touch.wl_touch, SDL_TOUCH_DEVICE_DIRECT, name_fmt);
         SDL_AddTouch((SDL_TouchID)(uintptr_t)seat->touch.wl_touch, SDL_TOUCH_DEVICE_DIRECT, name_fmt);
-   
-        /* Pinch gesture */
-        seat->touch.gesture_pinch = zwp_pointer_gestures_v1_get_pinch_gesture(seat->display->zwp_pointer_gestures, seat->pointer.wl_pointer);
-        zwp_pointer_gesture_pinch_v1_set_user_data(seat->touch.gesture_pinch, seat);
-        zwp_pointer_gesture_pinch_v1_add_listener(seat->touch.gesture_pinch, &gesture_pinch_listener, seat);
-
     } else if (!(capabilities & WL_SEAT_CAPABILITY_TOUCH) && seat->touch.wl_touch) {
     } else if (!(capabilities & WL_SEAT_CAPABILITY_TOUCH) && seat->touch.wl_touch) {
         Wayland_SeatDestroyTouch(seat);
         Wayland_SeatDestroyTouch(seat);
     }
     }

+ 5 - 1
src/video/wayland/SDL_waylandevents_c.h

@@ -123,10 +123,14 @@ typedef struct SDL_WaylandSeat
         struct wp_cursor_shape_device_v1 *cursor_shape;
         struct wp_cursor_shape_device_v1 *cursor_shape;
         struct zwp_locked_pointer_v1 *locked_pointer;
         struct zwp_locked_pointer_v1 *locked_pointer;
         struct zwp_confined_pointer_v1 *confined_pointer;
         struct zwp_confined_pointer_v1 *confined_pointer;
+        struct zwp_pointer_gesture_pinch_v1 *gesture_pinch;
 
 
         SDL_WindowData *focus;
         SDL_WindowData *focus;
         SDL_CursorData *current_cursor;
         SDL_CursorData *current_cursor;
 
 
+        // According to the spec, a seat can only have one active gesture of any type at a time.
+        SDL_WindowData *gesture_focus;
+
         Uint64 highres_timestamp_ns;
         Uint64 highres_timestamp_ns;
         Uint32 enter_serial;
         Uint32 enter_serial;
         SDL_MouseButtonFlags buttons_pressed;
         SDL_MouseButtonFlags buttons_pressed;
@@ -192,7 +196,6 @@ typedef struct SDL_WaylandSeat
         struct zwp_input_timestamps_v1 *timestamps;
         struct zwp_input_timestamps_v1 *timestamps;
         Uint64 highres_timestamp_ns;
         Uint64 highres_timestamp_ns;
         struct wl_list points;
         struct wl_list points;
-        struct zwp_pointer_gesture_pinch_v1 *gesture_pinch;
     } touch;
     } touch;
 
 
     struct
     struct
@@ -220,6 +223,7 @@ extern int Wayland_WaitEventTimeout(SDL_VideoDevice *_this, Sint64 timeoutNS);
 
 
 extern void Wayland_DisplayInitInputTimestampManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitInputTimestampManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitCursorShapeManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitCursorShapeManager(SDL_VideoData *display);
+extern void Wayland_DisplayInitPointerGestureManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitTabletManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitTabletManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitDataDeviceManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitDataDeviceManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitPrimarySelectionDeviceManager(SDL_VideoData *display);
 extern void Wayland_DisplayInitPrimarySelectionDeviceManager(SDL_VideoData *display);

+ 7 - 2
src/video/wayland/SDL_waylandvideo.c

@@ -1324,7 +1324,8 @@ static void handle_registry_global(void *data, struct wl_registry *registry, uin
     } else if (SDL_strcmp(interface, "wp_pointer_warp_v1") == 0) {
     } else if (SDL_strcmp(interface, "wp_pointer_warp_v1") == 0) {
         d->wp_pointer_warp_v1 = wl_registry_bind(d->registry, id, &wp_pointer_warp_v1_interface, 1);
         d->wp_pointer_warp_v1 = wl_registry_bind(d->registry, id, &wp_pointer_warp_v1_interface, 1);
     } else if (SDL_strcmp(interface, "zwp_pointer_gestures_v1") == 0) {
     } else if (SDL_strcmp(interface, "zwp_pointer_gestures_v1") == 0) {
-        d->zwp_pointer_gestures = wl_registry_bind(d->registry, id, &zwp_pointer_gestures_v1_interface, 1);
+        d->zwp_pointer_gestures = wl_registry_bind(d->registry, id, &zwp_pointer_gestures_v1_interface, SDL_min(version, 3));
+        Wayland_DisplayInitPointerGestureManager(d);
     }
     }
 #ifdef SDL_WL_FIXES_VERSION
 #ifdef SDL_WL_FIXES_VERSION
     else if (SDL_strcmp(interface, "wl_fixes") == 0) {
     else if (SDL_strcmp(interface, "wl_fixes") == 0) {
@@ -1649,7 +1650,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
     }
     }
 
 
     if (data->zwp_pointer_gestures) {
     if (data->zwp_pointer_gestures) {
-        zwp_pointer_gestures_v1_destroy(data->zwp_pointer_gestures);
+        if (zwp_pointer_gestures_v1_get_version(data->zwp_pointer_gestures) >= ZWP_POINTER_GESTURES_V1_RELEASE_SINCE_VERSION) {
+            zwp_pointer_gestures_v1_release(data->zwp_pointer_gestures);
+        } else {
+            zwp_pointer_gestures_v1_destroy(data->zwp_pointer_gestures);
+        }
         data->zwp_pointer_gestures = NULL;
         data->zwp_pointer_gestures = NULL;
     }
     }