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,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;
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 (wl_display_prepare_read(display) == -1) {
wl_display_dispatch_pending(display);
return;
}
wl_display_flush(display);
struct pollfd fds = (struct pollfd) { fd, POLLIN, 0 };
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);
}