From ad9233e6208917f0351fa605ddca1175c7408dec Mon Sep 17 00:00:00 2001 From: Camilla Berglund Date: Wed, 10 Aug 2016 00:33:07 +0200 Subject: [PATCH] X11: Clean up event wait timeout logic Simplify interface and implement timeout updating. --- src/x11_window.c | 70 +++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 6857db74..13effcd8 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -53,13 +53,11 @@ // This avoids blocking other threads via the per-display Xlib lock that also // covers GLX functions // -void selectDisplayConnection(struct timeval* timeout) +static GLFWbool waitForEvent(double* timeout) { fd_set fds; - int result, count; const int fd = ConnectionNumber(_glfw.x11.display); - - count = fd + 1; + int count = fd + 1; FD_ZERO(&fds); FD_SET(fd, &fds); @@ -69,15 +67,29 @@ void selectDisplayConnection(struct timeval* timeout) if (fd < _glfw.linux_js.inotify) count = _glfw.linux_js.inotify + 1; #endif - - // NOTE: Only retry on EINTR if there is no timeout, as select is not - // required to update it for the time elapsed - // TODO: Update timeout value manually - do + for (;;) { - result = select(count, &fds, NULL, NULL, timeout); + if (timeout) + { + const long seconds = (long) *timeout; + const long microseconds = (long) ((*timeout - seconds) * 1e6); + struct timeval tv = { seconds, microseconds }; + const uint64_t base = _glfwPlatformGetTimerValue(); + + const int result = select(count, &fds, NULL, NULL, &tv); + const int error = errno; + + *timeout -= (_glfwPlatformGetTimerValue() - base) / + (double) _glfwPlatformGetTimerFrequency(); + + if (result > 0) + return GLFW_TRUE; + if ((result == -1 && error == EINTR) || *timeout <= 0.0) + return GLFW_FALSE; + } + else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR) + return GLFW_TRUE; } - while (result == -1 && errno == EINTR && timeout == NULL); } // Returns whether the window is iconified @@ -818,7 +830,7 @@ static void pushSelectionToManager(_GLFWwindow* window) } } - selectDisplayConnection(NULL); + waitForEvent(NULL); } } @@ -1793,16 +1805,14 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, if (!_glfwPlatformWindowVisible(window) && _glfw.x11.NET_REQUEST_FRAME_EXTENTS) { - uint64_t base; XEvent event; + double timeout = 0.5; // Ensure _NET_FRAME_EXTENTS is set, allowing glfwGetWindowFrameSize to // function before the window is mapped sendEventToWM(window, _glfw.x11.NET_REQUEST_FRAME_EXTENTS, 0, 0, 0, 0, 0); - base = _glfwPlatformGetTimerValue(); - // HACK: Use a timeout because earlier versions of some window managers // (at least Unity, Fluxbox and Xfwm) failed to send the reply // They have been fixed but broken versions are still in the wild @@ -1813,21 +1823,12 @@ void _glfwPlatformGetWindowFrameSize(_GLFWwindow* window, isFrameExtentsEvent, (XPointer) window)) { - double remaining; - struct timeval timeout; - - remaining = 0.5 - (_glfwPlatformGetTimerValue() - base) / - (double) _glfwPlatformGetTimerFrequency(); - if (remaining <= 0.0) + if (!waitForEvent(&timeout)) { _glfwInputError(GLFW_PLATFORM_ERROR, "X11: The window manager has a broken _NET_REQUEST_FRAME_EXTENTS implementation; please report this issue"); return; } - - timeout.tv_sec = 0; - timeout.tv_usec = (long) (remaining * 1e6); - selectDisplayConnection(&timeout); } } @@ -2048,28 +2049,17 @@ void _glfwPlatformPollEvents(void) void _glfwPlatformWaitEvents(void) { while (!XPending(_glfw.x11.display)) - selectDisplayConnection(NULL); + waitForEvent(NULL); _glfwPlatformPollEvents(); } void _glfwPlatformWaitEventsTimeout(double timeout) { - const double deadline = timeout + _glfwPlatformGetTimerValue() / - (double) _glfwPlatformGetTimerFrequency(); - while (!XPending(_glfw.x11.display)) { - const double remaining = deadline - _glfwPlatformGetTimerValue() / - (double) _glfwPlatformGetTimerFrequency(); - if (remaining <= 0.0) - return; - - const long seconds = (long) remaining; - const long microseconds = (long) ((remaining - seconds) * 1e6); - struct timeval tv = { seconds, microseconds }; - - selectDisplayConnection(&tv); + if (!waitForEvent(&timeout)) + break; } _glfwPlatformPollEvents(); @@ -2261,7 +2251,7 @@ const char* _glfwPlatformGetClipboardString(_GLFWwindow* window) window->x11.handle, CurrentTime); while (!XCheckTypedEvent(_glfw.x11.display, SelectionNotify, &event)) - selectDisplayConnection(NULL); + waitForEvent(NULL); if (event.xselection.property == None) continue;