From 748ca81d4b71ef3127a939655080c9072f791fd7 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 23 Jan 2020 15:07:22 +0530 Subject: [PATCH] Wayland: Fix a freeze in rare circumstances when having multiple OS Windows Fixes #2307 Fixes #1722 --- docs/changelog.rst | 3 +++ glfw/backend_utils.c | 4 +++- glfw/backend_utils.h | 2 +- glfw/wl_window.c | 16 ++++++++++------ glfw/x11_window.c | 2 +- 5 files changed, 18 insertions(+), 9 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index 2a38fb3fd..74482920d 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -19,6 +19,9 @@ To update |kitty|, :doc:`follow the instructions `. - Allow choosing OpenType features for individual fonts via the :opt:`font_features` option. (:pull:`2248`) +- Wayland: Fix a freeze in rare circumstances when having multiple OS Windows + (:iss:`2307` and :iss:`1722`) + - Add an option :opt:`force_ltr` to turn off the display of text in RTL scripts in right-to-left order (:pull:`2293`) diff --git a/glfw/backend_utils.c b/glfw/backend_utils.c index 2a0f6fd7b..ad76bbb1c 100644 --- a/glfw/backend_utils.c +++ b/glfw/backend_utils.c @@ -292,7 +292,7 @@ finalizePollData(EventLoopData *eld) { } int -pollForEvents(EventLoopData *eld, monotonic_t timeout) { +pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func display_callback) { int read_ok = 0; timeout = prepareForPoll(eld, timeout); EVDBG("pollForEvents final timeout: %.3f", monotonic_t_to_s_double(timeout)); @@ -305,6 +305,7 @@ pollForEvents(EventLoopData *eld, monotonic_t timeout) { errno = 0; result = pollWithTimeout(eld->fds, eld->watches_count, timeout); int saved_errno = errno; + if (display_callback) display_callback(result, eld->fds[0].revents && eld->watches[0].events, NULL); dispatchTimers(eld); if (result > 0) { dispatchEvents(eld); @@ -319,6 +320,7 @@ pollForEvents(EventLoopData *eld, monotonic_t timeout) { errno = 0; result = poll(eld->fds, eld->watches_count, -1); int saved_errno = errno; + if (display_callback) display_callback(result, eld->fds[0].revents && eld->watches[0].events, NULL); dispatchTimers(eld); if (result > 0) { dispatchEvents(eld); diff --git a/glfw/backend_utils.h b/glfw/backend_utils.h index 3e1ff2abe..cb92dc7b3 100644 --- a/glfw/backend_utils.h +++ b/glfw/backend_utils.h @@ -90,7 +90,7 @@ void toggleTimer(EventLoopData *eld, id_type timer_id, int enabled); void changeTimerInterval(EventLoopData *eld, id_type timer_id, monotonic_t interval); monotonic_t prepareForPoll(EventLoopData *eld, monotonic_t timeout); int pollWithTimeout(struct pollfd *fds, nfds_t nfds, monotonic_t timeout); -int pollForEvents(EventLoopData *eld, monotonic_t timeout); +int pollForEvents(EventLoopData *eld, monotonic_t timeout, watch_callback_func); unsigned dispatchTimers(EventLoopData *eld); void finalizePollData(EventLoopData *eld); bool initPollData(EventLoopData *eld, int display_fd); diff --git a/glfw/wl_window.c b/glfw/wl_window.c index 154688420..5c7aa0c09 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -754,6 +754,13 @@ abortOnFatalError(int last_error) { _glfw.wl.eventLoopData.wakeup_data_read = true; } +static void +wayland_read_events(int poll_result, int events, void *data UNUSED) { + EVDBG("wayland_read_events poll_result: %d events: %d", poll_result, events); + if (poll_result > 0 && events) wl_display_read_events(_glfw.wl.display); + else wl_display_cancel_read(_glfw.wl.display); +} + static void handleEvents(monotonic_t timeout) { @@ -779,18 +786,15 @@ handleEvents(monotonic_t timeout) return; } - bool display_read_ok = pollForEvents(&_glfw.wl.eventLoopData, timeout); + // we pass in wayland_read_events to ensure that the above wl_display_prepare_read call + // is followed by either wl_display_cancel_read or wl_display_read_events + bool display_read_ok = pollForEvents(&_glfw.wl.eventLoopData, timeout, wayland_read_events); EVDBG("display_read_ok: %d", display_read_ok); if (display_read_ok) { - wl_display_read_events(display); int num = wl_display_dispatch_pending(display); (void)num; EVDBG("dispatched %d Wayland events", num); } - else - { - wl_display_cancel_read(display); - } glfw_ibus_dispatch(&_glfw.wl.xkb.ibus); glfw_dbus_session_bus_dispatch(); EVDBG("other dispatch done"); diff --git a/glfw/x11_window.c b/glfw/x11_window.c index 7cb1c3ace..102749ead 100644 --- a/glfw/x11_window.c +++ b/glfw/x11_window.c @@ -68,7 +68,7 @@ static unsigned _glfwDispatchX11Events(void); static void handleEvents(monotonic_t timeout) { EVDBG("starting handleEvents(%.2f)", monotonic_t_to_s_double(timeout)); - int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout); + int display_read_ok = pollForEvents(&_glfw.x11.eventLoopData, timeout, NULL); EVDBG("display_read_ok: %d", display_read_ok); if (display_read_ok) { unsigned dispatched = _glfwDispatchX11Events();