diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 031962ec..7a544eb6 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -79,6 +79,7 @@ video tutorials. - Jason Francis - Gerald Franz - Mário Freitas + - Friz64 - GeO4d - Marcus Geelnard - Gegy diff --git a/README.md b/README.md index b05132e7..ab346ae6 100644 --- a/README.md +++ b/README.md @@ -148,12 +148,17 @@ information on what to include when reporting a bug. potential segmentation fault (#2744) - [Wayland] Bugfix: Confining or disabling the cursor could segfault on compositors without `pointer-constraints-unstable-v1` + - [Wayland] Bugfix: Key repeat did not function on very old compositors + - [Wayland] Bugfix: The `libwayland-client` library was not unloaded at termination + - [Wayland] Bugfix: Scroll events were sent twice on some versions of GNOME (#2494) + - [Wayland] Bugfix: Two-dimensional scroll input was emitted as separate axes - [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631) - [X11] Bugfix: Occasional crash when an idle display awakes (#2766) - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale less than 1 (#2754) - [X11] Bugfix: Clamp width and height to >= 1 to prevent BadValue error and app exit - [X11] Bugfix: Floating windows silently became non-floating when hidden (#2276) + - [X11] Bugfix: The `libXext` library was not unloaded at termination - [Linux] Bugfix: The header for `ioctl` was only implicitly included (#2778) - [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface` - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` diff --git a/src/cocoa_init.m b/src/cocoa_init.m index 15dc4ec4..531d8b45 100644 --- a/src/cocoa_init.m +++ b/src/cocoa_init.m @@ -688,6 +688,8 @@ void _glfwTerminateCocoa(void) _glfwTerminateEGL(); _glfwTerminateOSMesa(); + memset(&_glfw.ns, 0, sizeof(_glfw.ns)); + } // autoreleasepool } diff --git a/src/egl_context.c b/src/egl_context.c index 921d5c6e..156adb40 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -312,18 +312,19 @@ static int extensionSupportedEGL(const char* extension) static GLFWglproc getProcAddressEGL(const char* procname) { - _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); - assert(window != NULL); + const GLFWglproc proc = (GLFWglproc) eglGetProcAddress(procname); + if (proc) + return proc; - if (window->context.egl.client) + if (!_glfw.egl.KHR_get_all_proc_addresses) { - GLFWglproc proc = (GLFWglproc) - _glfwPlatformGetModuleSymbol(window->context.egl.client, procname); - if (proc) - return proc; + _GLFWwindow* window = _glfwPlatformGetTls(&_glfw.contextSlot); + assert(window != NULL); + + return _glfwPlatformGetModuleSymbol(window->context.egl.client, procname); } - return eglGetProcAddress(procname); + return NULL; } static void destroyContextEGL(_GLFWwindow* window) @@ -333,11 +334,8 @@ static void destroyContextEGL(_GLFWwindow* window) if (_glfw.platform.platformID != GLFW_PLATFORM_X11 || window->context.client != GLFW_OPENGL_API) { - if (window->context.egl.client) - { - _glfwPlatformFreeModule(window->context.egl.client); - window->context.egl.client = NULL; - } + _glfwPlatformFreeModule(window->context.egl.client); + window->context.egl.client = NULL; } if (window->context.egl.surface) @@ -358,8 +356,6 @@ static void destroyContextEGL(_GLFWwindow* window) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Initialize EGL -// GLFWbool _glfwInitEGL(void) { int i; @@ -369,10 +365,10 @@ GLFWbool _glfwInitEGL(void) { #if defined(_GLFW_EGL_LIBRARY) _GLFW_EGL_LIBRARY, -#elif defined(_GLFW_WIN32) +#elif defined(_WIN32) "libEGL.dll", "EGL.dll", -#elif defined(_GLFW_COCOA) +#elif defined(__APPLE__) "libEGL.dylib", #elif defined(__CYGWIN__) "libEGL-1.so", @@ -545,8 +541,6 @@ GLFWbool _glfwInitEGL(void) return GLFW_TRUE; } -// Terminate EGL -// void _glfwTerminateEGL(void) { if (_glfw.egl.display) @@ -556,7 +550,7 @@ void _glfwTerminateEGL(void) } // Free modules only after all wayland termination functions are called - if (_glfw.egl.handle && _glfw.platform.platformID != GLFW_PLATFORM_WAYLAND) + if (_glfw.platform.platformID != GLFW_PLATFORM_WAYLAND) { _glfwPlatformFreeModule(_glfw.egl.handle); _glfw.egl.handle = NULL; @@ -570,8 +564,6 @@ void _glfwTerminateEGL(void) attribs[index++] = v; \ } -// Create the OpenGL or OpenGL ES context -// GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) @@ -769,10 +761,10 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { #if defined(_GLFW_GLESV1_LIBRARY) _GLFW_GLESV1_LIBRARY, -#elif defined(_GLFW_WIN32) +#elif defined(_WIN32) "GLESv1_CM.dll", "libGLES_CM.dll", -#elif defined(_GLFW_COCOA) +#elif defined(__APPLE__) "libGLESv1_CM.dylib", #elif defined(__OpenBSD__) || defined(__NetBSD__) "libGLESv1_CM.so", @@ -786,10 +778,10 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { #if defined(_GLFW_GLESV2_LIBRARY) _GLFW_GLESV2_LIBRARY, -#elif defined(_GLFW_WIN32) +#elif defined(_WIN32) "GLESv2.dll", "libGLESv2.dll", -#elif defined(_GLFW_COCOA) +#elif defined(__APPLE__) "libGLESv2.dylib", #elif defined(__CYGWIN__) "libGLESv2-2.so", @@ -804,8 +796,8 @@ GLFWbool _glfwCreateContextEGL(_GLFWwindow* window, { #if defined(_GLFW_OPENGL_LIBRARY) _GLFW_OPENGL_LIBRARY, -#elif defined(_GLFW_WIN32) -#elif defined(_GLFW_COCOA) +#elif defined(_WIN32) +#elif defined(__APPLE__) #elif defined(__OpenBSD__) || defined(__NetBSD__) "libGL.so", #else diff --git a/src/glx_context.c b/src/glx_context.c index 098c4bad..f08cdd5b 100644 --- a/src/glx_context.c +++ b/src/glx_context.c @@ -253,8 +253,6 @@ static void destroyContextGLX(_GLFWwindow* window) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Initialize GLX -// GLFWbool _glfwInitGLX(void) { const char* sonames[] = @@ -426,18 +424,13 @@ GLFWbool _glfwInitGLX(void) return GLFW_TRUE; } -// Terminate GLX -// void _glfwTerminateGLX(void) { // NOTE: This function must not call any X11 functions, as it is called // after XCloseDisplay (see _glfwTerminateX11 for details) - if (_glfw.glx.handle) - { - _glfwPlatformFreeModule(_glfw.glx.handle); - _glfw.glx.handle = NULL; - } + _glfwPlatformFreeModule(_glfw.glx.handle); + _glfw.glx.handle = NULL; } #define SET_ATTRIB(a, v) \ @@ -447,8 +440,6 @@ void _glfwTerminateGLX(void) attribs[index++] = v; \ } -// Create the OpenGL or OpenGL ES context -// GLFWbool _glfwCreateContextGLX(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) diff --git a/src/nsgl_context.m b/src/nsgl_context.m index df729800..cc676171 100644 --- a/src/nsgl_context.m +++ b/src/nsgl_context.m @@ -128,8 +128,6 @@ static void destroyContextNSGL(_GLFWwindow* window) ////// GLFW internal API ////// ////////////////////////////////////////////////////////////////////////// -// Initialize OpenGL support -// GLFWbool _glfwInitNSGL(void) { if (_glfw.nsgl.framework) @@ -147,14 +145,10 @@ GLFWbool _glfwInitNSGL(void) return GLFW_TRUE; } -// Terminate OpenGL support -// void _glfwTerminateNSGL(void) { } -// Create the OpenGL context -// GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) diff --git a/src/null_init.c b/src/null_init.c index 8c10f5e6..fd0d9e96 100644 --- a/src/null_init.c +++ b/src/null_init.c @@ -260,5 +260,6 @@ void _glfwTerminateNull(void) free(_glfw.null.clipboardString); _glfwTerminateOSMesa(); _glfwTerminateEGL(); + memset(&_glfw.null, 0, sizeof(_glfw.null)); } diff --git a/src/osmesa_context.c b/src/osmesa_context.c index 0bb375a8..c7a4c868 100644 --- a/src/osmesa_context.c +++ b/src/osmesa_context.c @@ -180,11 +180,8 @@ GLFWbool _glfwInitOSMesa(void) void _glfwTerminateOSMesa(void) { - if (_glfw.osmesa.handle) - { - _glfwPlatformFreeModule(_glfw.osmesa.handle); - _glfw.osmesa.handle = NULL; - } + _glfwPlatformFreeModule(_glfw.osmesa.handle); + _glfw.osmesa.handle = NULL; } #define SET_ATTRIB(a, v) \ diff --git a/src/posix_module.c b/src/posix_module.c index b3482d26..de99bc69 100644 --- a/src/posix_module.c +++ b/src/posix_module.c @@ -41,7 +41,8 @@ void* _glfwPlatformLoadModule(const char* path) void _glfwPlatformFreeModule(void* module) { - dlclose(module); + if (module) + dlclose(module); } GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name) diff --git a/src/vulkan.c b/src/vulkan.c index 9c87fcfe..b52a57fc 100644 --- a/src/vulkan.c +++ b/src/vulkan.c @@ -55,12 +55,13 @@ GLFWbool _glfwInitVulkan(int mode) { #if defined(_GLFW_VULKAN_LIBRARY) _glfw.vk.handle = _glfwPlatformLoadModule(_GLFW_VULKAN_LIBRARY); -#elif defined(_GLFW_WIN32) +#elif defined(_WIN32) _glfw.vk.handle = _glfwPlatformLoadModule("vulkan-1.dll"); #elif defined(_GLFW_COCOA) _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.1.dylib"); if (!_glfw.vk.handle) _glfw.vk.handle = _glfwLoadLocalVulkanLoaderCocoa(); +#elif defined(__APPLE__) #elif defined(__OpenBSD__) || defined(__NetBSD__) _glfw.vk.handle = _glfwPlatformLoadModule("libvulkan.so"); #else @@ -157,8 +158,8 @@ GLFWbool _glfwInitVulkan(int mode) void _glfwTerminateVulkan(void) { - if (_glfw.vk.handle) - _glfwPlatformFreeModule(_glfw.vk.handle); + _glfwPlatformFreeModule(_glfw.vk.handle); + _glfw.vk.handle = NULL; } const char* _glfwGetVulkanResultString(VkResult result) diff --git a/src/wgl_context.c b/src/wgl_context.c index 3c7d71c2..1fb7d322 100644 --- a/src/wgl_context.c +++ b/src/wgl_context.c @@ -401,8 +401,6 @@ static void destroyContextWGL(_GLFWwindow* window) } } -// Initialize WGL -// GLFWbool _glfwInitWGL(void) { PIXELFORMATDESCRIPTOR pfd; @@ -521,12 +519,10 @@ GLFWbool _glfwInitWGL(void) return GLFW_TRUE; } -// Terminate WGL -// void _glfwTerminateWGL(void) { - if (_glfw.wgl.instance) - _glfwPlatformFreeModule(_glfw.wgl.instance); + _glfwPlatformFreeModule(_glfw.wgl.instance); + _glfw.wgl.instance = NULL; } #define SET_ATTRIB(a, v) \ @@ -536,8 +532,6 @@ void _glfwTerminateWGL(void) attribs[index++] = v; \ } -// Create the OpenGL or OpenGL ES context -// GLFWbool _glfwCreateContextWGL(_GLFWwindow* window, const _GLFWctxconfig* ctxconfig, const _GLFWfbconfig* fbconfig) diff --git a/src/win32_init.c b/src/win32_init.c index 90e47670..d526fe8a 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -166,29 +166,6 @@ static GLFWbool loadLibraries(void) return GLFW_TRUE; } -// Unload used libraries (DLLs) -// -static void freeLibraries(void) -{ - if (_glfw.win32.xinput.instance) - _glfwPlatformFreeModule(_glfw.win32.xinput.instance); - - if (_glfw.win32.dinput8.instance) - _glfwPlatformFreeModule(_glfw.win32.dinput8.instance); - - if (_glfw.win32.user32.instance) - _glfwPlatformFreeModule(_glfw.win32.user32.instance); - - if (_glfw.win32.dwmapi.instance) - _glfwPlatformFreeModule(_glfw.win32.dwmapi.instance); - - if (_glfw.win32.shcore.instance) - _glfwPlatformFreeModule(_glfw.win32.shcore.instance); - - if (_glfw.win32.ntdll.instance) - _glfwPlatformFreeModule(_glfw.win32.ntdll.instance); -} - // Create key code translation tables // static void createKeyTables(void) @@ -721,7 +698,14 @@ void _glfwTerminateWin32(void) _glfwTerminateEGL(); _glfwTerminateOSMesa(); - freeLibraries(); + _glfwPlatformFreeModule(_glfw.win32.xinput.instance); + _glfwPlatformFreeModule(_glfw.win32.dinput8.instance); + _glfwPlatformFreeModule(_glfw.win32.user32.instance); + _glfwPlatformFreeModule(_glfw.win32.dwmapi.instance); + _glfwPlatformFreeModule(_glfw.win32.shcore.instance); + _glfwPlatformFreeModule(_glfw.win32.ntdll.instance); + + memset(&_glfw.win32, 0, sizeof(_glfw.win32)); } #endif // _GLFW_WIN32 diff --git a/src/win32_module.c b/src/win32_module.c index b76599b6..ca5ce9cf 100644 --- a/src/win32_module.c +++ b/src/win32_module.c @@ -39,7 +39,8 @@ void* _glfwPlatformLoadModule(const char* path) void _glfwPlatformFreeModule(void* module) { - FreeLibrary((HMODULE) module); + if (module) + FreeLibrary((HMODULE) module); } GLFWproc _glfwPlatformGetModuleSymbol(void* module, const char* name) diff --git a/src/wl_init.c b/src/wl_init.c index 1d0d3ef8..1e527649 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -135,15 +135,8 @@ static void registryHandleGlobal(void* userData, { _glfw.wl.seat = wl_registry_bind(registry, name, &wl_seat_interface, - _glfw_min(4, version)); + _glfw_min(5, version)); _glfwAddSeatListenerWayland(_glfw.wl.seat); - - if (wl_seat_get_version(_glfw.wl.seat) >= - WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) - { - _glfw.wl.keyRepeatTimerfd = - timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); - } } } else if (strcmp(interface, "wl_data_device_manager") == 0) @@ -834,6 +827,16 @@ int _glfwInitWayland(void) createKeyTables(); + _glfw.wl.keyRepeatTimerfd = + timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC | TFD_NONBLOCK); + if (_glfw.wl.keyRepeatTimerfd == -1) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: Failed to create timerfd: %s", + strerror(errno)); + return GLFW_FALSE; + } + _glfw.wl.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!_glfw.wl.xkb.context) { @@ -981,37 +984,16 @@ void _glfwTerminateWayland(void) // Free modules only after all Wayland termination functions are called - if (_glfw.egl.handle) - { - _glfwPlatformFreeModule(_glfw.egl.handle); - _glfw.egl.handle = NULL; - } - - if (_glfw.wl.libdecor.handle) - { - _glfwPlatformFreeModule(_glfw.wl.libdecor.handle); - _glfw.wl.libdecor.handle = NULL; - } - - if (_glfw.wl.egl.handle) - { - _glfwPlatformFreeModule(_glfw.wl.egl.handle); - _glfw.wl.egl.handle = NULL; - } - - if (_glfw.wl.xkb.handle) - { - _glfwPlatformFreeModule(_glfw.wl.xkb.handle); - _glfw.wl.xkb.handle = NULL; - } - - if (_glfw.wl.cursor.handle) - { - _glfwPlatformFreeModule(_glfw.wl.cursor.handle); - _glfw.wl.cursor.handle = NULL; - } + _glfwPlatformFreeModule(_glfw.egl.handle); + _glfwPlatformFreeModule(_glfw.wl.libdecor.handle); + _glfwPlatformFreeModule(_glfw.wl.egl.handle); + _glfwPlatformFreeModule(_glfw.wl.xkb.handle); + _glfwPlatformFreeModule(_glfw.wl.cursor.handle); + _glfwPlatformFreeModule(_glfw.wl.client.handle); _glfw_free(_glfw.wl.clipboardString); + + memset(&_glfw.wl, 0, sizeof(_glfw.wl)); } #endif // _GLFW_WAYLAND diff --git a/src/wl_platform.h b/src/wl_platform.h index c2ddb732..c9d1c251 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -414,7 +414,8 @@ typedef struct _GLFWwindowWayland GLFWbool decorations; struct wl_buffer* buffer; _GLFWfallbackEdgeWayland top, left, right, bottom; - wl_fixed_t pointerX, pointerY; + double pointerX, pointerY; + uint32_t buttonPressSerial; const char* cursorName; } fallback; } _GLFWwindowWayland; @@ -472,6 +473,17 @@ typedef struct _GLFWlibraryWayland short int scancodes[GLFW_KEY_LAST + 1]; char keynames[GLFW_KEY_LAST + 1][5]; + struct { + struct wl_surface* pointerSurface; + unsigned int events; + double pointerX; + double pointerY; + double scrollX; + double scrollY; + int button; + int action; + } pending; + struct { void* handle; struct xkb_context* context; diff --git a/src/wl_window.c b/src/wl_window.c index b00b8ced..dd097cf9 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -55,6 +55,11 @@ #define GLFW_BORDER_SIZE 4 #define GLFW_CAPTION_HEIGHT 24 +#define GLFW_PENDING_SURFACE 1 +#define GLFW_PENDING_BUTTON 2 +#define GLFW_PENDING_MOTION 4 +#define GLFW_PENDING_SCROLL 8 + static int createTmpfileCloexec(char* tmpname) { int fd; @@ -278,15 +283,11 @@ static void destroyFallbackDecorations(_GLFWwindow* window) destroyFallbackEdge(&window->wl.fallback.bottom); } -static void updateFallbackDecorationCursor(_GLFWwindow* window, - wl_fixed_t sx, - wl_fixed_t sy) +static void updateFallbackDecorationCursor(_GLFWwindow* window, double xpos, double ypos) { - window->wl.fallback.pointerX = sx; - window->wl.fallback.pointerY = sy; + window->wl.fallback.pointerX = xpos; + window->wl.fallback.pointerY = ypos; - const double xpos = wl_fixed_to_double(sx); - const double ypos = wl_fixed_to_double(sy); const char* cursorName = "left_ptr"; if (window->resizable) @@ -361,18 +362,16 @@ static void updateFallbackDecorationCursor(_GLFWwindow* window, } } -static void handleFallbackDecorationButton(_GLFWwindow* window, - uint32_t serial, - uint32_t button, - uint32_t state) +static void handleFallbackDecorationButton(_GLFWwindow* window, int button, int action) { - if (state != WL_POINTER_BUTTON_STATE_PRESSED) + if (action != GLFW_PRESS) return; - const double xpos = wl_fixed_to_double(window->wl.fallback.pointerX); - const double ypos = wl_fixed_to_double(window->wl.fallback.pointerY); + const double xpos = window->wl.fallback.pointerX; + const double ypos = window->wl.fallback.pointerY; + const uint32_t serial = window->wl.fallback.buttonPressSerial; - if (button == BTN_LEFT) + if (button == GLFW_MOUSE_BUTTON_LEFT) { uint32_t edges = XDG_TOPLEVEL_RESIZE_EDGE_NONE; @@ -410,7 +409,7 @@ static void handleFallbackDecorationButton(_GLFWwindow* window, if (edges != XDG_TOPLEVEL_RESIZE_EDGE_NONE) xdg_toplevel_resize(window->wl.xdg.toplevel, _glfw.wl.seat, serial, edges); } - else if (button == BTN_RIGHT) + else if (button == GLFW_MOUSE_BUTTON_RIGHT) { if (!window->wl.xdg.toplevel) return; @@ -421,10 +420,8 @@ static void handleFallbackDecorationButton(_GLFWwindow* window, if (ypos < GLFW_BORDER_SIZE) return; - xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, - _glfw.wl.seat, serial, - xpos, - ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE); + xdg_toplevel_show_window_menu(window->wl.xdg.toplevel, _glfw.wl.seat, serial, + xpos, ypos - GLFW_CAPTION_HEIGHT - GLFW_BORDER_SIZE); } } @@ -1522,6 +1519,70 @@ static char* readDataOfferAsString(struct wl_data_offer* offer, const char* mime return string; } +static void processPointerEnterSurface(struct wl_surface* surface) +{ + _glfw.wl.pointerSurface = surface; + + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + if (window->wl.surface == _glfw.wl.pointerSurface) + { + _glfwSetCursorWayland(window, window->cursor); + _glfwInputCursorEnter(window, GLFW_TRUE); + } +} + +static void processPointerLeaveSurface(struct wl_surface* surface) +{ + _glfw.wl.pointerSurface = NULL; + + _GLFWwindow* window = wl_surface_get_user_data(surface); + if (window->wl.surface == surface) + _glfwInputCursorEnter(window, GLFW_FALSE); + else + { + if (window->wl.fallback.decorations) + window->wl.fallback.cursorName = NULL; + } +} + +static void processPointerMotion(double xpos, double ypos) +{ + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + if (window->wl.surface == _glfw.wl.pointerSurface) + { + if (window->cursorMode != GLFW_CURSOR_DISABLED) + { + window->wl.cursorPosX = xpos; + window->wl.cursorPosY = ypos; + _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY); + } + } + else + { + if (window->wl.fallback.decorations) + updateFallbackDecorationCursor(window, xpos, ypos); + } +} + +static void processPointerButton(int button, int action) +{ + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + if (window->wl.surface == _glfw.wl.pointerSurface) + _glfwInputMouseClick(window, button, action, _glfw.wl.xkb.modifiers); + else + { + if (window->wl.fallback.decorations) + handleFallbackDecorationButton(window, button, action); + } +} + +static void processPointerScroll(double xoffset, double yoffset) +{ + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + if (window->wl.surface == _glfw.wl.pointerSurface) + _glfwInputScroll(window, xoffset, yoffset); +} + static void pointerHandleEnter(void* userData, struct wl_pointer* pointer, uint32_t serial, @@ -1538,25 +1599,21 @@ static void pointerHandleEnter(void* userData, _glfw.wl.serial = serial; _glfw.wl.pointerEnterSerial = serial; - _glfw.wl.pointerSurface = surface; - _GLFWwindow* window = wl_surface_get_user_data(surface); - if (window->wl.surface == surface) + const double xpos = wl_fixed_to_double(sx); + const double ypos = wl_fixed_to_double(sy); + + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) { - _glfwSetCursorWayland(window, window->cursor); - _glfwInputCursorEnter(window, GLFW_TRUE); - - if (window->cursorMode != GLFW_CURSOR_DISABLED) - { - window->wl.cursorPosX = wl_fixed_to_double(sx); - window->wl.cursorPosY = wl_fixed_to_double(sy); - _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY); - } + _glfw.wl.pending.events |= (GLFW_PENDING_SURFACE | GLFW_PENDING_MOTION); + _glfw.wl.pending.pointerSurface = surface; + _glfw.wl.pending.pointerX = xpos; + _glfw.wl.pending.pointerY = ypos; } else { - if (window->wl.fallback.decorations) - updateFallbackDecorationCursor(window, sx, sy); + processPointerEnterSurface(surface); + processPointerMotion(xpos, ypos); } } @@ -1572,16 +1629,14 @@ static void pointerHandleLeave(void* userData, return; _glfw.wl.serial = serial; - _glfw.wl.pointerSurface = NULL; - _GLFWwindow* window = wl_surface_get_user_data(surface); - if (window->wl.surface == surface) - _glfwInputCursorEnter(window, GLFW_FALSE); - else + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) { - if (window->wl.fallback.decorations) - window->wl.fallback.cursorName = NULL; + _glfw.wl.pending.events |= GLFW_PENDING_SURFACE; + _glfw.wl.pending.pointerSurface = NULL; } + else + processPointerLeaveSurface(surface); } static void pointerHandleMotion(void* userData, @@ -1593,50 +1648,49 @@ static void pointerHandleMotion(void* userData, if (!_glfw.wl.pointerSurface) return; - _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); + const double xpos = wl_fixed_to_double(sx); + const double ypos = wl_fixed_to_double(sy); - if (window->cursorMode == GLFW_CURSOR_DISABLED) - return; - - if (window->wl.surface == _glfw.wl.pointerSurface) + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) { - window->wl.cursorPosX = wl_fixed_to_double(sx); - window->wl.cursorPosY = wl_fixed_to_double(sy); - _glfwInputCursorPos(window, window->wl.cursorPosX, window->wl.cursorPosY); + _glfw.wl.pending.events |= GLFW_PENDING_MOTION; + _glfw.wl.pending.pointerX = xpos; + _glfw.wl.pending.pointerY = ypos; } else - { - if (window->wl.fallback.decorations) - updateFallbackDecorationCursor(window, sx, sy); - } + processPointerMotion(xpos, ypos); } static void pointerHandleButton(void* userData, struct wl_pointer* pointer, uint32_t serial, uint32_t time, - uint32_t button, + uint32_t buttonID, uint32_t state) { if (!_glfw.wl.pointerSurface) return; + _glfw.wl.serial = serial; + + const int button = buttonID - BTN_LEFT; + const int action = (state == WL_POINTER_BUTTON_STATE_PRESSED); + _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); - - if (window->wl.surface == _glfw.wl.pointerSurface) + if (window->wl.fallback.decorations) { - _glfw.wl.serial = serial; + if (action == GLFW_PRESS) + window->wl.fallback.buttonPressSerial = serial; + } - _glfwInputMouseClick(window, - button - BTN_LEFT, - state == WL_POINTER_BUTTON_STATE_PRESSED, - _glfw.wl.xkb.modifiers); + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) + { + _glfw.wl.pending.events |= GLFW_PENDING_BUTTON; + _glfw.wl.pending.button = button; + _glfw.wl.pending.action = action; } else - { - if (window->wl.fallback.decorations) - handleFallbackDecorationButton(window, serial, button, state); - } + processPointerButton(button, action); } static void pointerHandleAxis(void* userData, @@ -1648,18 +1702,70 @@ static void pointerHandleAxis(void* userData, if (!_glfw.wl.pointerSurface) return; - _GLFWwindow* window = wl_surface_get_user_data(_glfw.wl.pointerSurface); - - if (window->wl.surface == _glfw.wl.pointerSurface) + if (wl_pointer_get_version(pointer) >= WL_POINTER_FRAME_SINCE_VERSION) + { + _glfw.wl.pending.events |= GLFW_PENDING_SCROLL; + if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) + _glfw.wl.pending.scrollX = -wl_fixed_to_double(value) / 10.0; + else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) + _glfw.wl.pending.scrollY = -wl_fixed_to_double(value) / 10.0; + } + else { // NOTE: 10 units of motion per mouse wheel step seems to be a common ratio if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) - _glfwInputScroll(window, -wl_fixed_to_double(value) / 10.0, 0.0); + processPointerScroll(-wl_fixed_to_double(value) / 10.0, 0.0); else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) - _glfwInputScroll(window, 0.0, -wl_fixed_to_double(value) / 10.0); + processPointerScroll(0.0, -wl_fixed_to_double(value) / 10.0); } } +static void pointerHandleFrame(void* userData, struct wl_pointer* pointer) +{ + if (_glfw.wl.pending.events & GLFW_PENDING_SURFACE) + { + if (_glfw.wl.pointerSurface) + processPointerLeaveSurface(_glfw.wl.pointerSurface); + + if (_glfw.wl.pending.pointerSurface) + processPointerEnterSurface(_glfw.wl.pending.pointerSurface); + } + + if (!_glfw.wl.pointerSurface) + return; + + if (_glfw.wl.pending.events & GLFW_PENDING_MOTION) + processPointerMotion(_glfw.wl.pending.pointerX, _glfw.wl.pending.pointerY); + + if (_glfw.wl.pending.events & GLFW_PENDING_BUTTON) + processPointerButton(_glfw.wl.pending.button, _glfw.wl.pending.action); + + if (_glfw.wl.pending.events & GLFW_PENDING_SCROLL) + processPointerScroll(_glfw.wl.pending.scrollX, _glfw.wl.pending.scrollY); + + memset(&_glfw.wl.pending, 0, sizeof(_glfw.wl.pending)); +} + +static void pointerHandleAxisSource(void* userData, + struct wl_pointer* pointer, + uint32_t axisSource) +{ +} + +static void pointerHandleAxisStop(void* userData, + struct wl_pointer* pointer, + uint32_t time, + uint32_t axis) +{ +} + +static void pointerHandleAxisDiscrete(void* userData, + struct wl_pointer* pointer, + uint32_t axis, + int32_t discrete) +{ +} + static const struct wl_pointer_listener pointerListener = { pointerHandleEnter, @@ -1667,6 +1773,10 @@ static const struct wl_pointer_listener pointerListener = pointerHandleMotion, pointerHandleButton, pointerHandleAxis, + pointerHandleFrame, + pointerHandleAxisSource, + pointerHandleAxisStop, + pointerHandleAxisDiscrete }; static void keyboardHandleKeymap(void* userData, @@ -1942,6 +2052,13 @@ static void seatHandleCapabilities(void* userData, { _glfw.wl.keyboard = wl_seat_get_keyboard(seat); wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL); + + if (wl_keyboard_get_version(_glfw.wl.keyboard) < + WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) + { + _glfw.wl.keyRepeatRate = 4; + _glfw.wl.keyRepeatDelay = 500; + } } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard) { diff --git a/src/x11_init.c b/src/x11_init.c index 6b34c263..b0acbf7f 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -1592,65 +1592,29 @@ void _glfwTerminateX11(void) _glfw.x11.display = NULL; } - if (_glfw.x11.x11xcb.handle) - { - _glfwPlatformFreeModule(_glfw.x11.x11xcb.handle); - _glfw.x11.x11xcb.handle = NULL; - } - - if (_glfw.x11.xcursor.handle) - { - _glfwPlatformFreeModule(_glfw.x11.xcursor.handle); - _glfw.x11.xcursor.handle = NULL; - } - - if (_glfw.x11.randr.handle) - { - _glfwPlatformFreeModule(_glfw.x11.randr.handle); - _glfw.x11.randr.handle = NULL; - } - - if (_glfw.x11.xinerama.handle) - { - _glfwPlatformFreeModule(_glfw.x11.xinerama.handle); - _glfw.x11.xinerama.handle = NULL; - } - - if (_glfw.x11.xrender.handle) - { - _glfwPlatformFreeModule(_glfw.x11.xrender.handle); - _glfw.x11.xrender.handle = NULL; - } - - if (_glfw.x11.vidmode.handle) - { - _glfwPlatformFreeModule(_glfw.x11.vidmode.handle); - _glfw.x11.vidmode.handle = NULL; - } - - if (_glfw.x11.xi.handle) - { - _glfwPlatformFreeModule(_glfw.x11.xi.handle); - _glfw.x11.xi.handle = NULL; - } - _glfwTerminateOSMesa(); // NOTE: These need to be unloaded after XCloseDisplay, as they register // cleanup callbacks that get called by that function _glfwTerminateEGL(); _glfwTerminateGLX(); - if (_glfw.x11.xlib.handle) - { - _glfwPlatformFreeModule(_glfw.x11.xlib.handle); - _glfw.x11.xlib.handle = NULL; - } + _glfwPlatformFreeModule(_glfw.x11.x11xcb.handle); + _glfwPlatformFreeModule(_glfw.x11.xcursor.handle); + _glfwPlatformFreeModule(_glfw.x11.randr.handle); + _glfwPlatformFreeModule(_glfw.x11.xinerama.handle); + _glfwPlatformFreeModule(_glfw.x11.xrender.handle); + _glfwPlatformFreeModule(_glfw.x11.xshape.handle); + _glfwPlatformFreeModule(_glfw.x11.vidmode.handle); + _glfwPlatformFreeModule(_glfw.x11.xi.handle); + _glfwPlatformFreeModule(_glfw.x11.xlib.handle); if (_glfw.x11.emptyEventPipe[0] || _glfw.x11.emptyEventPipe[1]) { close(_glfw.x11.emptyEventPipe[0]); close(_glfw.x11.emptyEventPipe[1]); } + + memset(&_glfw.x11, 0, sizeof(_glfw.x11)); } #endif // _GLFW_X11