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.
This commit is contained in:
ManoloFLTK
2026-01-04 09:38:16 +01:00
parent 62c2497ff5
commit 357336bd40
@@ -1368,25 +1368,39 @@ static const struct wl_registry_listener registry_listener = {
extern int fl_send_system_handlers(void *); 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 (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 }; struct pollfd fds = (struct pollfd) { fd, POLLIN, 0 };
do { if (poll(&fds, 1, 0) <= 0) {
if (wl_display_dispatch(display) == -1) { wl_display_cancel_read(display);
int err = wl_display_get_error(display); return;
if (err == EPROTO) { }
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; const struct wl_interface *interface;
int code = wl_display_get_protocol_error(display, &interface, NULL); int code = wl_display_get_protocol_error(display, &interface, NULL);
Fl::fatal("Fatal error no %d in Wayland protocol: %s", code, Fl::fatal("Fatal error %d in Wayland protocol: %s",
(interface ? interface->name : "unknown") ); code, (interface ? interface->name : "unknown") );
} else { } else {
Fl::fatal("Fatal error while communicating with the Wayland server: %s", Fl::fatal("Fatal error while communicating with Wayland server: %s",
strerror(errno)); strerror(errno));
} }
} }
}
while (poll(&fds, 1, 0) > 0);
}
Fl_Wayland_Screen_Driver::Fl_Wayland_Screen_Driver() : Fl_Unix_Screen_Driver() { Fl_Wayland_Screen_Driver::Fl_Wayland_Screen_Driver() : Fl_Unix_Screen_Driver() {