فهرست منبع

wayland: Implement 'DISABLED' cursor mode

This implements support for the 'DISABLED' cursor mode, which
effectively means locking the pointer to the surface. The cursor is also
explicitly hidden.

This adds two new build dependencies: wayland-scanner and
wayland-protocols.

Closes #708.
Jonas Ådahl 9 سال پیش
والد
کامیت
cb08dc574c
7فایلهای تغییر یافته به همراه182 افزوده شده و 10 حذف شده
  1. 4 0
      .gitignore
  2. 26 0
      CMake/modules/FindWaylandProtocols.cmake
  3. 2 0
      CMakeLists.txt
  4. 9 0
      src/CMakeLists.txt
  5. 14 5
      src/wl_init.c
  6. 9 0
      src/wl_platform.h
  7. 118 5
      src/wl_window.c

+ 4 - 0
.gitignore

@@ -30,6 +30,10 @@ src/glfw_config.h
 src/glfw3.pc
 src/glfw3.pc
 src/glfw3Config.cmake
 src/glfw3Config.cmake
 src/glfw3ConfigVersion.cmake
 src/glfw3ConfigVersion.cmake
+src/wayland-pointer-constraints-unstable-v1-client-protocol.h
+src/wayland-pointer-constraints-unstable-v1-protocol.c
+src/wayland-relative-pointer-unstable-v1-client-protocol.h
+src/wayland-relative-pointer-unstable-v1-protocol.c
 
 
 # Compiled binaries
 # Compiled binaries
 src/libglfw.so
 src/libglfw.so

+ 26 - 0
CMake/modules/FindWaylandProtocols.cmake

@@ -0,0 +1,26 @@
+find_package(PkgConfig)
+
+pkg_check_modules(WaylandProtocols QUIET wayland-protocols>=${WaylandProtocols_FIND_VERSION})
+
+execute_process(COMMAND ${PKG_CONFIG_EXECUTABLE} --variable=pkgdatadir wayland-protocols
+                OUTPUT_VARIABLE WaylandProtocols_PKGDATADIR
+                RESULT_VARIABLE _pkgconfig_failed)
+if (_pkgconfig_failed)
+    message(FATAL_ERROR "Missing wayland-protocols pkgdatadir")
+endif()
+
+string(REGEX REPLACE "[\r\n]" "" WaylandProtocols_PKGDATADIR "${WaylandProtocols_PKGDATADIR}")
+
+find_package_handle_standard_args(WaylandProtocols
+    FOUND_VAR
+        WaylandProtocols_FOUND
+    REQUIRED_VARS
+        WaylandProtocols_PKGDATADIR
+    VERSION_VAR
+        WaylandProtocols_VERSION
+    HANDLE_COMPONENTS
+)
+
+set(WAYLAND_PROTOCOLS_FOUND ${WaylandProtocols_FOUND})
+set(WAYLAND_PROTOCOLS_PKGDATADIR ${WaylandProtocols_PKGDATADIR})
+set(WAYLAND_PROTOCOLS_VERSION ${WaylandProtocols_VERSION})

+ 2 - 0
CMakeLists.txt

@@ -275,6 +275,8 @@ if (_GLFW_WAYLAND)
     set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
     set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH})
 
 
     find_package(Wayland REQUIRED)
     find_package(Wayland REQUIRED)
+    find_package(WaylandScanner REQUIRED)
+    find_package(WaylandProtocols 1.1 REQUIRED)
 
 
     list(APPEND glfw_PKG_DEPS "wayland-egl")
     list(APPEND glfw_PKG_DEPS "wayland-egl")
 
 

+ 9 - 0
src/CMakeLists.txt

@@ -24,6 +24,15 @@ elseif (_GLFW_WAYLAND)
                      posix_time.h posix_tls.h xkb_unicode.h)
                      posix_time.h posix_tls.h xkb_unicode.h)
     set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c
     set(glfw_SOURCES ${common_SOURCES} wl_init.c wl_monitor.c wl_window.c
                      linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c)
                      linux_joystick.c posix_time.c posix_tls.c xkb_unicode.c)
+
+    ecm_add_wayland_client_protocol(glfw_SOURCES
+        PROTOCOL
+        ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml
+        BASENAME relative-pointer-unstable-v1)
+    ecm_add_wayland_client_protocol(glfw_SOURCES
+        PROTOCOL
+        ${WAYLAND_PROTOCOLS_PKGDATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
+        BASENAME pointer-constraints-unstable-v1)
 elseif (_GLFW_MIR)
 elseif (_GLFW_MIR)
     set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h
     set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h
                      posix_time.h posix_tls.h xkb_unicode.h)
                      posix_time.h posix_tls.h xkb_unicode.h)

+ 14 - 5
src/wl_init.c

@@ -84,12 +84,7 @@ static void pointerHandleMotion(void* data,
         return;
         return;
 
 
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
     if (window->cursorMode == GLFW_CURSOR_DISABLED)
-    {
-        /* TODO */
-        _glfwInputError(GLFW_PLATFORM_ERROR,
-                        "Wayland: GLFW_CURSOR_DISABLED not supported");
         return;
         return;
-    }
     else
     else
     {
     {
         window->wl.cursorPosX = wl_fixed_to_double(sx);
         window->wl.cursorPosX = wl_fixed_to_double(sx);
@@ -413,6 +408,20 @@ static void registryHandleGlobal(void* data,
             wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
             wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
         }
         }
     }
     }
+    else if (strcmp(interface, "zwp_relative_pointer_manager_v1") == 0)
+    {
+        _glfw.wl.relativePointerManager =
+            wl_registry_bind(registry, name,
+                             &zwp_relative_pointer_manager_v1_interface,
+                             1);
+    }
+    else if (strcmp(interface, "zwp_pointer_constraints_v1") == 0)
+    {
+        _glfw.wl.pointerConstraints =
+            wl_registry_bind(registry, name,
+                             &zwp_pointer_constraints_v1_interface,
+                             1);
+    }
 }
 }
 
 
 static void registryHandleGlobalRemove(void *data,
 static void registryHandleGlobalRemove(void *data,

+ 9 - 0
src/wl_platform.h

@@ -56,6 +56,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR
  #error "The Wayland backend depends on EGL platform support"
  #error "The Wayland backend depends on EGL platform support"
 #endif
 #endif
 
 
+#include "wayland-relative-pointer-unstable-v1-client-protocol.h"
+#include "wayland-pointer-constraints-unstable-v1-client-protocol.h"
+
 #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
 #define _glfw_dlopen(name) dlopen(name, RTLD_LAZY | RTLD_LOCAL)
 #define _glfw_dlclose(handle) dlclose(handle)
 #define _glfw_dlclose(handle) dlclose(handle)
 #define _glfw_dlsym(handle, name) dlsym(handle, name)
 #define _glfw_dlsym(handle, name) dlsym(handle, name)
@@ -95,6 +98,10 @@ typedef struct _GLFWwindowWayland
     int                         monitorsCount;
     int                         monitorsCount;
     int                         monitorsSize;
     int                         monitorsSize;
 
 
+    struct {
+        struct zwp_relative_pointer_v1*    relativePointer;
+        struct zwp_locked_pointer_v1*      lockedPointer;
+    } pointerLock;
 } _GLFWwindowWayland;
 } _GLFWwindowWayland;
 
 
 
 
@@ -110,6 +117,8 @@ typedef struct _GLFWlibraryWayland
     struct wl_seat*             seat;
     struct wl_seat*             seat;
     struct wl_pointer*          pointer;
     struct wl_pointer*          pointer;
     struct wl_keyboard*         keyboard;
     struct wl_keyboard*         keyboard;
+    struct zwp_relative_pointer_manager_v1* relativePointerManager;
+    struct zwp_pointer_constraints_v1*      pointerConstraints;
 
 
     int                         wl_compositor_version;
     int                         wl_compositor_version;
 
 

+ 118 - 5
src/wl_window.c

@@ -529,11 +529,17 @@ void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)
         *ypos = window->wl.cursorPosY;
         *ypos = window->wl.cursorPosY;
 }
 }
 
 
+static GLFWbool isPointerLocked(_GLFWwindow* window);
+
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
 void _glfwPlatformSetCursorPos(_GLFWwindow* window, double x, double y)
 {
 {
-    // A Wayland client can not set the cursor position
-    _glfwInputError(GLFW_PLATFORM_ERROR,
-                    "Wayland: Cursor position setting not supported");
+    if (isPointerLocked(window))
+    {
+        zwp_locked_pointer_v1_set_cursor_position_hint(
+            window->wl.pointerLock.lockedPointer,
+            wl_fixed_from_double(x), wl_fixed_from_double(y));
+        wl_surface_commit(window->wl.surface);
+    }
 }
 }
 
 
 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
 void _glfwPlatformSetCursorMode(_GLFWwindow* window, int mode)
@@ -631,6 +637,103 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor)
         wl_buffer_destroy(cursor->wl.buffer);
         wl_buffer_destroy(cursor->wl.buffer);
 }
 }
 
 
+static void handleRelativeMotion(void* data,
+                                 struct zwp_relative_pointer_v1* pointer,
+                                 uint32_t timeHi,
+                                 uint32_t timeLo,
+                                 wl_fixed_t dx,
+                                 wl_fixed_t dy,
+                                 wl_fixed_t dxUnaccel,
+                                 wl_fixed_t dyUnaccel)
+{
+    _GLFWwindow* window = data;
+
+    if (window->cursorMode != GLFW_CURSOR_DISABLED)
+        return;
+
+    _glfwInputCursorMotion(window,
+                           wl_fixed_to_double(dxUnaccel),
+                           wl_fixed_to_double(dyUnaccel));
+}
+
+static const struct zwp_relative_pointer_v1_listener relativePointerListener = {
+    handleRelativeMotion
+};
+
+static void handleLocked(void* data,
+                         struct zwp_locked_pointer_v1* lockedPointer)
+{
+}
+
+static void unlockPointer(_GLFWwindow* window)
+{
+    struct zwp_relative_pointer_v1* relativePointer =
+        window->wl.pointerLock.relativePointer;
+    struct zwp_locked_pointer_v1* lockedPointer =
+        window->wl.pointerLock.lockedPointer;
+
+    zwp_relative_pointer_v1_destroy(relativePointer);
+    zwp_locked_pointer_v1_destroy(lockedPointer);
+
+    window->wl.pointerLock.relativePointer = NULL;
+    window->wl.pointerLock.lockedPointer = NULL;
+}
+
+static void lockPointer(_GLFWwindow* window);
+
+static void handleUnlocked(void* data,
+                           struct zwp_locked_pointer_v1* lockedPointer)
+{
+}
+
+static const struct zwp_locked_pointer_v1_listener lockedPointerListener = {
+    handleLocked,
+    handleUnlocked
+};
+
+static void lockPointer(_GLFWwindow* window)
+{
+    struct zwp_relative_pointer_v1* relativePointer;
+    struct zwp_locked_pointer_v1* lockedPointer;
+
+    if (!_glfw.wl.relativePointerManager)
+    {
+        _glfwInputError(GLFW_PLATFORM_ERROR,
+                        "Wayland: no relative pointer manager");
+        return;
+    }
+
+    relativePointer =
+        zwp_relative_pointer_manager_v1_get_relative_pointer(
+            _glfw.wl.relativePointerManager,
+            _glfw.wl.pointer);
+    zwp_relative_pointer_v1_add_listener(relativePointer,
+                                         &relativePointerListener,
+                                         window);
+
+    lockedPointer =
+        zwp_pointer_constraints_v1_lock_pointer(
+            _glfw.wl.pointerConstraints,
+            window->wl.surface,
+            _glfw.wl.pointer,
+            NULL,
+            ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
+    zwp_locked_pointer_v1_add_listener(lockedPointer,
+                                       &lockedPointerListener,
+                                       window);
+
+    window->wl.pointerLock.relativePointer = relativePointer;
+    window->wl.pointerLock.lockedPointer = lockedPointer;
+
+    wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
+                          NULL, 0, 0);
+}
+
+static GLFWbool isPointerLocked(_GLFWwindow* window)
+{
+    return window->wl.pointerLock.lockedPointer != NULL;
+}
+
 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
 void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
 {
 {
     struct wl_buffer* buffer;
     struct wl_buffer* buffer;
@@ -648,6 +751,10 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
     if (window != _glfw.wl.pointerFocus)
     if (window != _glfw.wl.pointerFocus)
         return;
         return;
 
 
+    // Unlock possible pointer lock if no longer disabled.
+    if (window->cursorMode != GLFW_CURSOR_DISABLED && isPointerLocked(window))
+        unlockPointer(window);
+
     if (window->cursorMode == GLFW_CURSOR_NORMAL)
     if (window->cursorMode == GLFW_CURSOR_NORMAL)
     {
     {
         if (cursor)
         if (cursor)
@@ -691,9 +798,15 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor)
             wl_surface_commit(surface);
             wl_surface_commit(surface);
         }
         }
     }
     }
-    else /* Cursor is hidden set cursor surface to NULL */
+    else if (window->cursorMode == GLFW_CURSOR_DISABLED)
+    {
+        if (!isPointerLocked(window))
+            lockPointer(window);
+    }
+    else if (window->cursorMode == GLFW_CURSOR_HIDDEN)
     {
     {
-        wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, NULL, 0, 0);
+        wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial,
+                              NULL, 0, 0);
     }
     }
 }
 }