From 357336bd40d868fd65e95c61d1adaf9de0fb7811 Mon Sep 17 00:00:00 2001 From: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> Date: Sun, 4 Jan 2026 09:38:16 +0100 Subject: Fix "Wayland's wl_display_dispatch() can block a Vulkan application" (#1354) This rewriting of the FLTK callback function that runs when there are data available for reading in the socket connecting the app and the Wayland compositor is meant to facilitate the integration of Vulkan. This rewriting reproduces the recommended code to read from the socket documented in Wayland function wl_display_prepare_read_queue() when several threads potentially read from the socket. --- src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx | 44 ++++++++++++++++-------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx index 215f3650d..a0911cb51 100644 --- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx +++ b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx @@ -1368,24 +1368,38 @@ static const struct wl_registry_listener registry_listener = { extern int fl_send_system_handlers(void *); -static void wayland_socket_callback(int fd, struct wl_display *display) { +static void wayland_socket_callback(int fd, struct wl_display *display) +{ if (fl_send_system_handlers(NULL)) return; + if (wl_display_prepare_read(display) == -1) { + wl_display_dispatch_pending(display); + return; + } + wl_display_flush(display); struct pollfd fds = (struct pollfd) { fd, POLLIN, 0 }; - do { - if (wl_display_dispatch(display) == -1) { - int err = wl_display_get_error(display); - if (err == EPROTO) { - const struct wl_interface *interface; - int code = wl_display_get_protocol_error(display, &interface, NULL); - Fl::fatal("Fatal error no %d in Wayland protocol: %s", code, - (interface ? interface->name : "unknown") ); - } else { - Fl::fatal("Fatal error while communicating with the Wayland server: %s", - strerror(errno)); - } - } + if (poll(&fds, 1, 0) <= 0) { + wl_display_cancel_read(display); + return; + } + if (fds.revents & (POLLERR | POLLHUP)) { + wl_display_cancel_read(display); + goto fatal; + } + if (wl_display_read_events(display) == -1) + goto fatal; + if (wl_display_dispatch_pending(display) == -1) + goto fatal; + return; +fatal: + if (wl_display_get_error(display) == EPROTO) { + const struct wl_interface *interface; + int code = wl_display_get_protocol_error(display, &interface, NULL); + Fl::fatal("Fatal error %d in Wayland protocol: %s", + code, (interface ? interface->name : "unknown") ); + } else { + Fl::fatal("Fatal error while communicating with Wayland server: %s", + strerror(errno)); } - while (poll(&fds, 1, 0) > 0); } -- cgit v1.2.3