From e3b6fda0eab0c327de059505563314236a60e175 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 9 Dec 2015 14:03:32 +0800 Subject: [PATCH 1/2] wayland: Use modules from ECM for finding Wayland deps We were using a copied FindWayland cmake script, but lets use the ones from ECM (extra-cmake-modules) instead. This is more important in the future when building extensions from wayland-protocols. --- CMake/modules/FindWayland.cmake | 66 --------------------------------- CMakeLists.txt | 8 +++- 2 files changed, 6 insertions(+), 68 deletions(-) delete mode 100644 CMake/modules/FindWayland.cmake diff --git a/CMake/modules/FindWayland.cmake b/CMake/modules/FindWayland.cmake deleted file mode 100644 index f93218b87..000000000 --- a/CMake/modules/FindWayland.cmake +++ /dev/null @@ -1,66 +0,0 @@ -# Try to find Wayland on a Unix system -# -# This will define: -# -# WAYLAND_FOUND - True if Wayland is found -# WAYLAND_LIBRARIES - Link these to use Wayland -# WAYLAND_INCLUDE_DIR - Include directory for Wayland -# WAYLAND_DEFINITIONS - Compiler flags for using Wayland -# -# In addition the following more fine grained variables will be defined: -# -# WAYLAND_CLIENT_FOUND WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES -# WAYLAND_SERVER_FOUND WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES -# WAYLAND_EGL_FOUND WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES -# -# Copyright (c) 2013 Martin Gräßlin -# -# Redistribution and use is allowed according to the terms of the BSD license. -# For details see the accompanying COPYING-CMAKE-SCRIPTS file. - -IF (NOT WIN32) - IF (WAYLAND_INCLUDE_DIR AND WAYLAND_LIBRARIES) - # In the cache already - SET(WAYLAND_FIND_QUIETLY TRUE) - ENDIF () - - # Use pkg-config to get the directories and then use these values - # in the FIND_PATH() and FIND_LIBRARY() calls - FIND_PACKAGE(PkgConfig) - PKG_CHECK_MODULES(PKG_WAYLAND QUIET wayland-client wayland-server wayland-egl wayland-cursor) - - SET(WAYLAND_DEFINITIONS ${PKG_WAYLAND_CFLAGS}) - - FIND_PATH(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - FIND_PATH(WAYLAND_SERVER_INCLUDE_DIR NAMES wayland-server.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - FIND_PATH(WAYLAND_EGL_INCLUDE_DIR NAMES wayland-egl.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - FIND_PATH(WAYLAND_CURSOR_INCLUDE_DIR NAMES wayland-cursor.h HINTS ${PKG_WAYLAND_INCLUDE_DIRS}) - - FIND_LIBRARY(WAYLAND_CLIENT_LIBRARIES NAMES wayland-client HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - FIND_LIBRARY(WAYLAND_SERVER_LIBRARIES NAMES wayland-server HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - FIND_LIBRARY(WAYLAND_EGL_LIBRARIES NAMES wayland-egl HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - FIND_LIBRARY(WAYLAND_CURSOR_LIBRARIES NAMES wayland-cursor HINTS ${PKG_WAYLAND_LIBRARY_DIRS}) - - set(WAYLAND_INCLUDE_DIR ${WAYLAND_CLIENT_INCLUDE_DIR} ${WAYLAND_SERVER_INCLUDE_DIR} ${WAYLAND_EGL_INCLUDE_DIR} ${WAYLAND_CURSOR_INCLUDE_DIR}) - - set(WAYLAND_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES} ${WAYLAND_SERVER_LIBRARIES} ${WAYLAND_EGL_LIBRARIES} ${WAYLAND_CURSOR_LIBRARIES}) - - list(REMOVE_DUPLICATES WAYLAND_INCLUDE_DIR) - - include(FindPackageHandleStandardArgs) - - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CLIENT DEFAULT_MSG WAYLAND_CLIENT_LIBRARIES WAYLAND_CLIENT_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_SERVER DEFAULT_MSG WAYLAND_SERVER_LIBRARIES WAYLAND_SERVER_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_EGL DEFAULT_MSG WAYLAND_EGL_LIBRARIES WAYLAND_EGL_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND_CURSOR DEFAULT_MSG WAYLAND_CURSOR_LIBRARIES WAYLAND_CURSOR_INCLUDE_DIR) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(WAYLAND DEFAULT_MSG WAYLAND_LIBRARIES WAYLAND_INCLUDE_DIR) - - MARK_AS_ADVANCED( - WAYLAND_INCLUDE_DIR WAYLAND_LIBRARIES - WAYLAND_CLIENT_INCLUDE_DIR WAYLAND_CLIENT_LIBRARIES - WAYLAND_SERVER_INCLUDE_DIR WAYLAND_SERVER_LIBRARIES - WAYLAND_EGL_INCLUDE_DIR WAYLAND_EGL_LIBRARIES - WAYLAND_CURSOR_INCLUDE_DIR WAYLAND_CURSOR_LIBRARIES - ) - -ENDIF () diff --git a/CMakeLists.txt b/CMakeLists.txt index e6585a1c7..20927d4e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -286,11 +286,15 @@ endif() # Use Wayland for window creation #-------------------------------------------------------------------- if (_GLFW_WAYLAND) + find_package(ECM REQUIRED NO_MODULE) + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) + find_package(Wayland REQUIRED) + list(APPEND glfw_PKG_DEPS "wayland-egl") - list(APPEND glfw_INCLUDE_DIRS "${WAYLAND_INCLUDE_DIR}") - list(APPEND glfw_LIBRARIES "${WAYLAND_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") + list(APPEND glfw_INCLUDE_DIRS "${Wayland_INCLUDE_DIR}") + list(APPEND glfw_LIBRARIES "${Wayland_LIBRARIES}" "${CMAKE_THREAD_LIBS_INIT}") find_package(XKBCommon REQUIRED) list(APPEND glfw_PKG_DEPS "xkbcommon") From 3754b8e976e8004ffa87cdf881c4a15bc9baf0a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 9 Dec 2015 15:29:37 +0800 Subject: [PATCH 2/2] wayland: Implement support for 'DISABLED' cusror 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 --- .gitignore | 4 + CMake/modules/FindWaylandProtocols.cmake | 26 +++++ CMakeLists.txt | 2 + src/CMakeLists.txt | 9 ++ src/wl_init.c | 19 +++- src/wl_platform.h | 9 ++ src/wl_window.c | 123 ++++++++++++++++++++++- 7 files changed, 182 insertions(+), 10 deletions(-) create mode 100644 CMake/modules/FindWaylandProtocols.cmake diff --git a/.gitignore b/.gitignore index 61ba29b93..c2450f75c 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,10 @@ src/glfw_config.h src/glfw3.pc src/glfw3Config.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 src/libglfw.so diff --git a/CMake/modules/FindWaylandProtocols.cmake b/CMake/modules/FindWaylandProtocols.cmake new file mode 100644 index 000000000..8eb83f27e --- /dev/null +++ b/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}) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20927d4e0..2d761fa44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -290,6 +290,8 @@ if (_GLFW_WAYLAND) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) find_package(Wayland REQUIRED) + find_package(WaylandScanner REQUIRED) + find_package(WaylandProtocols 1.1 REQUIRED) list(APPEND glfw_PKG_DEPS "wayland-egl") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d44f873c9..dab94ef12 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,15 @@ elseif (_GLFW_WAYLAND) posix_time.h posix_tls.h xkb_unicode.h) 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) + + 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) set(glfw_HEADERS ${common_HEADERS} mir_platform.h linux_joystick.h posix_time.h posix_tls.h xkb_unicode.h) diff --git a/src/wl_init.c b/src/wl_init.c index 90dc507be..29509ae91 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -84,12 +84,7 @@ static void pointerHandleMotion(void* data, return; if (window->cursorMode == GLFW_CURSOR_DISABLED) - { - /* TODO */ - _glfwInputError(GLFW_PLATFORM_ERROR, - "Wayland: GLFW_CURSOR_DISABLED not supported"); return; - } else { 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); } } + 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, diff --git a/src/wl_platform.h b/src/wl_platform.h index 56ce16311..100b12bc0 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -56,6 +56,9 @@ typedef VkBool32 (APIENTRY *PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR #error "The Wayland backend depends on EGL platform support" #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_dlclose(handle) dlclose(handle) #define _glfw_dlsym(handle, name) dlsym(handle, name) @@ -95,6 +98,10 @@ typedef struct _GLFWwindowWayland int monitorsCount; int monitorsSize; + struct { + struct zwp_relative_pointer_v1* relativePointer; + struct zwp_locked_pointer_v1* lockedPointer; + } pointerLock; } _GLFWwindowWayland; @@ -110,6 +117,8 @@ typedef struct _GLFWlibraryWayland struct wl_seat* seat; struct wl_pointer* pointer; struct wl_keyboard* keyboard; + struct zwp_relative_pointer_manager_v1* relativePointerManager; + struct zwp_pointer_constraints_v1* pointerConstraints; int wl_compositor_version; diff --git a/src/wl_window.c b/src/wl_window.c index 75aa912e4..e6ed4d04c 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -518,11 +518,17 @@ void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) *ypos = window->wl.cursorPosY; } +static GLFWbool isPointerLocked(_GLFWwindow* window); + 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) @@ -620,6 +626,103 @@ void _glfwPlatformDestroyCursor(_GLFWcursor* cursor) 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) { struct wl_buffer* buffer; @@ -637,6 +740,10 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) if (window != _glfw.wl.pointerFocus) 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 (cursor) @@ -680,9 +787,15 @@ void _glfwPlatformSetCursor(_GLFWwindow* window, _GLFWcursor* cursor) wl_surface_commit(surface); } } - else /* Cursor is hidden set cursor surface to NULL */ + else if (window->cursorMode == GLFW_CURSOR_DISABLED) { - wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.pointerSerial, NULL, 0, 0); + 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); } }