Wayland: Improve event processing with timeout

If the polling was interrupted by a signal or by incomplete or unrelated
data on any file descriptor, handleEvents could return before the full
timeout had elapsed.

This retries the Wayland prepare-to-read and poll until the full timeout
has elapsed or until any event was processed.  Unfortunately, due to how
the Wayland client API is designed, this also includes the delete_id
for the frame callback created by eglSwapBuffers.

This means glfwWaitEvents* are still not fully functional on Wayland.
See #1911 for more details.
This commit is contained in:
Camilla Löwy 2022-03-03 22:41:36 +01:00
parent a32cbf6d4f
commit 71742d9a27

View File

@ -737,6 +737,7 @@ static GLFWbool flushDisplay(void)
static void handleEvents(double* timeout) static void handleEvents(double* timeout)
{ {
GLFWbool event = GLFW_FALSE;
struct pollfd fds[] = struct pollfd fds[] =
{ {
{ wl_display_get_fd(_glfw.wl.display), POLLIN }, { wl_display_get_fd(_glfw.wl.display), POLLIN },
@ -744,31 +745,38 @@ static void handleEvents(double* timeout)
{ _glfw.wl.cursorTimerfd, POLLIN }, { _glfw.wl.cursorTimerfd, POLLIN },
}; };
while (wl_display_prepare_read(_glfw.wl.display) != 0) while (!event)
wl_display_dispatch_pending(_glfw.wl.display);
// If an error other than EAGAIN happens, we have likely been disconnected
// from the Wayland session; try to handle that the best we can.
if (!flushDisplay())
{ {
wl_display_cancel_read(_glfw.wl.display); while (wl_display_prepare_read(_glfw.wl.display) != 0)
wl_display_dispatch_pending(_glfw.wl.display);
_GLFWwindow* window = _glfw.windowListHead; // If an error other than EAGAIN happens, we have likely been disconnected
while (window) // from the Wayland session; try to handle that the best we can.
if (!flushDisplay())
{ {
_glfwInputWindowCloseRequest(window); wl_display_cancel_read(_glfw.wl.display);
window = window->next;
_GLFWwindow* window = _glfw.windowListHead;
while (window)
{
_glfwInputWindowCloseRequest(window);
window = window->next;
}
return;
} }
return; if (!_glfwPollPOSIX(fds, 3, timeout))
} {
wl_display_cancel_read(_glfw.wl.display);
return;
}
if (_glfwPollPOSIX(fds, 3, timeout))
{
if (fds[0].revents & POLLIN) if (fds[0].revents & POLLIN)
{ {
wl_display_read_events(_glfw.wl.display); wl_display_read_events(_glfw.wl.display);
wl_display_dispatch_pending(_glfw.wl.display); if (wl_display_dispatch_pending(_glfw.wl.display) > 0)
event = GLFW_TRUE;
} }
else else
wl_display_cancel_read(_glfw.wl.display); wl_display_cancel_read(_glfw.wl.display);
@ -789,6 +797,8 @@ static void handleEvents(double* timeout)
_glfwInputTextWayland(_glfw.wl.keyboardFocus, _glfwInputTextWayland(_glfw.wl.keyboardFocus,
_glfw.wl.keyboardLastScancode); _glfw.wl.keyboardLastScancode);
} }
event = GLFW_TRUE;
} }
} }
@ -797,11 +807,12 @@ static void handleEvents(double* timeout)
uint64_t repeats; uint64_t repeats;
if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8) if (read(_glfw.wl.cursorTimerfd, &repeats, sizeof(repeats)) == 8)
{
incrementCursorImage(_glfw.wl.pointerFocus); incrementCursorImage(_glfw.wl.pointerFocus);
event = GLFW_TRUE;
}
} }
} }
else
wl_display_cancel_read(_glfw.wl.display);
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////