diff --git a/glfw/wl_init.c b/glfw/wl_init.c index 1df2b0a77..80a3271fa 100644 --- a/glfw/wl_init.c +++ b/glfw/wl_init.c @@ -24,6 +24,7 @@ // //======================================================================== +#define _GNU_SOURCE #include "internal.h" #include @@ -33,6 +34,7 @@ #include #include #include +#include #include @@ -615,6 +617,13 @@ static const struct wl_registry_listener registryListener = { int _glfwPlatformInit(void) { + if (pipe2(_glfw.wl.eventLoopData.wakeupFds, O_CLOEXEC | O_NONBLOCK) != 0) + { + _glfwInputError(GLFW_PLATFORM_ERROR, + "Wayland: failed to create self pipe"); + return GLFW_FALSE; + } + _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0"); if (!_glfw.wl.cursor.handle) { @@ -654,6 +663,10 @@ int _glfwPlatformInit(void) "Wayland: Failed to connect to display"); return GLFW_FALSE; } + _glfw.wl.eventLoopData.fds[0].fd = _glfw.wl.eventLoopData.wakeupFds[0]; + _glfw.wl.eventLoopData.fds[1].fd = wl_display_get_fd(_glfw.wl.display); + _glfw.wl.eventLoopData.fds[0].events = POLLIN; + _glfw.wl.eventLoopData.fds[1].events = POLLIN; _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display); wl_registry_add_listener(_glfw.wl.registry, ®istryListener, NULL); @@ -691,6 +704,17 @@ int _glfwPlatformInit(void) void _glfwPlatformTerminate(void) { + if (_glfw.wl.eventLoopData.wakeupFds[0] > 0) + { + close(_glfw.wl.eventLoopData.wakeupFds[0]); + _glfw.wl.eventLoopData.wakeupFds[0] = -1; + } + if (_glfw.wl.eventLoopData.wakeupFds[1] > 0) + { + close(_glfw.wl.eventLoopData.wakeupFds[1]); + _glfw.wl.eventLoopData.wakeupFds[1] = -1; + } + #ifdef __linux__ _glfwTerminateJoysticksLinux(); #endif diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index 2da58b8b4..f0e408fe8 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -26,6 +26,7 @@ #include #include +#include typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; @@ -228,6 +229,11 @@ typedef struct _GLFWlibraryWayland PFN_wl_egl_window_resize window_resize; } egl; + struct { + struct pollfd fds[2]; + int wakeupFds[2]; + } eventLoopData; + } _GLFWlibraryWayland; // Wayland-specific per-monitor data diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 92817a61b..082cd7c53 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -700,21 +700,30 @@ dispatchPendingKeyRepeats() { } } -static int -adjustTimeoutForKeyRepeat(int timeout) { +static double +adjustTimeoutForKeyRepeat(double timeout) { if (_glfw.wl.keyRepeatInfo.nextRepeatAt <= 0 || _glfw.wl.keyRepeatInfo.keyboardFocus != _glfw.wl.keyboardFocus || _glfw.wl.keyboardRepeatRate == 0) return timeout; double now = glfwGetTime(); - if (timeout < 0 || now + timeout / 1000. > _glfw.wl.keyRepeatInfo.nextRepeatAt) { - timeout = _glfw.wl.keyRepeatInfo.nextRepeatAt <= now ? 0 : ( (_glfw.wl.keyRepeatInfo.nextRepeatAt - now) * 1000 + 1 ); + if (timeout < 0 || now + timeout > _glfw.wl.keyRepeatInfo.nextRepeatAt) { + timeout = _glfw.wl.keyRepeatInfo.nextRepeatAt <= now ? 0 : ( (_glfw.wl.keyRepeatInfo.nextRepeatAt - now) + 0.001 ); } return timeout; } +#ifdef __NetBSD__ +#define ppoll pollts +#endif + +static inline void +drainFd(int fd) { + static char drain_buf[64]; + while(read(fd, drain_buf, sizeof(drain_buf)) < 0 && errno == EINTR); +} + static void -handleEvents(int timeout) +handleEvents(double timeout) { struct wl_display* display = _glfw.wl.display; - struct pollfd pfd = { wl_display_get_fd(display), POLLIN }; while (wl_display_prepare_read(display) != 0) wl_display_dispatch_pending(display); @@ -736,19 +745,27 @@ handleEvents(int timeout) dispatchPendingKeyRepeats(); timeout = adjustTimeoutForKeyRepeat(timeout); + GLFWbool read_ok = GLFW_FALSE; - if (poll(&pfd, 1, timeout) > 0) - { - if (pfd.revents & POLLIN) + if (timeout >= 0) { + const long seconds = (long) timeout; + const long nanoseconds = (long) ((timeout - seconds) * 1e9); + struct timespec tv = { seconds, nanoseconds }; + const int result = ppoll(_glfw.wl.eventLoopData.fds, 2, &tv, NULL); + if (result > 0) { - wl_display_read_events(display); - wl_display_dispatch_pending(display); + if (_glfw.wl.eventLoopData.fds[0].revents && POLLIN) drainFd(_glfw.wl.eventLoopData.fds[0].fd); + read_ok = _glfw.wl.eventLoopData.fds[1].revents && POLLIN; } - else - { - wl_display_cancel_read(display); + } else { + if (poll(_glfw.wl.eventLoopData.fds, 2, -1) > 0) { + if (_glfw.wl.eventLoopData.fds[0].revents && POLLIN) drainFd(_glfw.wl.eventLoopData.fds[0].fd); + read_ok = _glfw.wl.eventLoopData.fds[1].revents && POLLIN; } - + } + if (read_ok) { + wl_display_read_events(display); + wl_display_dispatch_pending(display); } else { @@ -1206,12 +1223,13 @@ void _glfwPlatformWaitEvents(void) void _glfwPlatformWaitEventsTimeout(double timeout) { - handleEvents((int) (timeout * 1e3)); + handleEvents(timeout); } void _glfwPlatformPostEmptyEvent(void) { wl_display_sync(_glfw.wl.display); + while (write(_glfw.wl.eventLoopData.wakeupFds[1], "w", 1) < 0 && errno == EINTR); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos) diff --git a/glfw/x11_init.c b/glfw/x11_init.c index 78f0021e2..8b7e04799 100644 --- a/glfw/x11_init.c +++ b/glfw/x11_init.c @@ -25,6 +25,7 @@ // //======================================================================== +#define _GNU_SOURCE #include "internal.h" #include @@ -590,24 +591,6 @@ Cursor _glfwCreateCursorX11(const GLFWimage* image, int xhot, int yhot) return cursor; } -static inline GLFWbool -selfPipe(int fds[2]) { - int flags; - flags = pipe(fds); - if (flags != 0) return GLFW_FALSE; - for (int i = 0; i < 2; i++) { - flags = fcntl(fds[i], F_GETFD); - if (flags == -1) { return GLFW_FALSE; } - if (fcntl(fds[i], F_SETFD, flags | FD_CLOEXEC) == -1) { return GLFW_FALSE; } - flags = fcntl(fds[i], F_GETFL); - if (flags == -1) { return GLFW_FALSE; } - if (fcntl(fds[i], F_SETFL, flags | O_NONBLOCK) == -1) { return GLFW_FALSE; } - } - return GLFW_TRUE; -} - - - ////////////////////////////////////////////////////////////////////////// ////// GLFW platform API ////// ////////////////////////////////////////////////////////////////////////// @@ -617,7 +600,7 @@ int _glfwPlatformInit(void) XInitThreads(); XrmInitialize(); - if (!selfPipe(_glfw.x11.eventLoopData.wakeupFds)) + if (pipe2(_glfw.x11.eventLoopData.wakeupFds, O_CLOEXEC | O_NONBLOCK) != 0) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: failed to create self pipe"); @@ -706,8 +689,8 @@ void _glfwPlatformTerminate(void) } if (_glfw.x11.eventLoopData.wakeupFds[1] > 0) { - _glfw.x11.eventLoopData.wakeupFds[1] = -1; close(_glfw.x11.eventLoopData.wakeupFds[1]); + _glfw.x11.eventLoopData.wakeupFds[1] = -1; } _glfw.x11.eventLoopData.fds[0].fd = -1; } diff --git a/glfw/x11_window.c b/glfw/x11_window.c index 6db24266d..be99cbafb 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -25,6 +25,7 @@ // //======================================================================== +#define _GNU_SOURCE #include "internal.h" #include @@ -51,16 +52,12 @@ static inline void drainFd(int fd) { static char drain_buf[64]; - while(1) { - ssize_t len = read(fd, drain_buf, sizeof(drain_buf)); - if (len < 0) { - if (errno == EINTR) continue; - break; - } - break; - } + while(read(fd, drain_buf, sizeof(drain_buf)) < 0 && errno == EINTR); } +#ifdef __NetBSD__ +#define ppoll pollts +#endif // Wait for data to arrive using poll // This avoids blocking other threads via the per-display Xlib lock that also @@ -82,9 +79,11 @@ static GLFWbool waitForEvent(double* timeout) for (nfds_t i = 0; i < count; i++) _glfw.x11.eventLoopData.fds[i].revents = 0; if (timeout) { - const int milliseconds = (int) ((*timeout) * 1000); + const long seconds = (long) *timeout; + const long nanoseconds = (long) ((*timeout - seconds) * 1e9); + struct timespec tv = { seconds, nanoseconds }; const uint64_t base = _glfwPlatformGetTimerValue(); - const int result = poll(_glfw.x11.eventLoopData.fds, count, milliseconds); + const int result = ppoll(_glfw.x11.eventLoopData.fds, count, &tv, NULL); *timeout -= (_glfwPlatformGetTimerValue() - base) / (double) _glfwPlatformGetTimerFrequency(); @@ -2612,11 +2611,7 @@ void _glfwPlatformPostEmptyEvent(void) XSendEvent(_glfw.x11.display, _glfw.x11.helperWindowHandle, False, 0, &event); XFlush(_glfw.x11.display); - while(1) - { - if (write(_glfw.x11.eventLoopData.wakeupFds[1], "w", 1) >= 0 || errno != EINTR) - break; - } + while (write(_glfw.x11.eventLoopData.wakeupFds[1], "w", 1) < 0 && errno == EINTR); } void _glfwPlatformGetCursorPos(_GLFWwindow* window, double* xpos, double* ypos)