GHOST/Wayland: replace roundtrip with dispatch_pending
Add a non-blocking version wrapper for wl_display_dispatch_pending. This uses roughly the same logic as Wayland_PumpEvents in SDL. Noticed this when investigating T100855. Note that performing a round-trip doesn't seem necessary from looking into QT/GTK & SDL event handling loops.
This commit is contained in:
parent
c5b36aa940
commit
deb8ae6bd1
Notes:
blender-bot
2023-02-14 11:24:03 +01:00
Referenced by commit 2a17fd40a5
, Fix non-interactive window borders after changes to event handling
|
@ -310,6 +310,11 @@ elseif(WITH_GHOST_X11 OR WITH_GHOST_WAYLAND)
|
|||
add_definitions(-DHAVE_MEMFD_CREATE)
|
||||
endif()
|
||||
|
||||
check_symbol_exists(poll "poll.h" HAVE_POLL)
|
||||
if(HAVE_POLL)
|
||||
add_definitions(-DHAVE_POLL)
|
||||
endif()
|
||||
|
||||
list(APPEND SRC
|
||||
intern/GHOST_SystemWayland.cpp
|
||||
intern/GHOST_WindowWayland.cpp
|
||||
|
|
|
@ -69,6 +69,10 @@
|
|||
#include <cstring>
|
||||
#include <mutex>
|
||||
|
||||
#ifdef HAVE_POLL
|
||||
# include <poll.h>
|
||||
#endif
|
||||
|
||||
/* Logging, use `ghost.wl.*` prefix. */
|
||||
#include "CLG_log.h"
|
||||
|
||||
|
@ -1456,6 +1460,85 @@ static int memfd_create_sealed(const char *name)
|
|||
#endif /* !HAVE_MEMFD_CREATE */
|
||||
}
|
||||
|
||||
enum {
|
||||
GWL_IOR_READ = 1 << 0,
|
||||
GWL_IOR_WRITE = 1 << 1,
|
||||
GWL_IOR_NO_RETRY = 1 << 2,
|
||||
};
|
||||
|
||||
static int file_descriptor_is_io_ready(int fd, const int flags, const int timeout_ms)
|
||||
{
|
||||
int result;
|
||||
|
||||
GHOST_ASSERT(flags & (GWL_IOR_READ | GWL_IOR_WRITE), "X");
|
||||
|
||||
/* Note: We don't bother to account for elapsed time if we get EINTR */
|
||||
do {
|
||||
#ifdef HAVE_POLL
|
||||
struct pollfd info;
|
||||
|
||||
info.fd = fd;
|
||||
info.events = 0;
|
||||
if (flags & GWL_IOR_READ) {
|
||||
info.events |= POLLIN | POLLPRI;
|
||||
}
|
||||
if (flags & GWL_IOR_WRITE) {
|
||||
info.events |= POLLOUT;
|
||||
}
|
||||
result = poll(&info, 1, timeout_ms);
|
||||
#else
|
||||
fd_set rfdset, *rfdp = nullptr;
|
||||
fd_set wfdset, *wfdp = nullptr;
|
||||
struct timeval tv, *tvp = nullptr;
|
||||
|
||||
/* If this assert triggers we'll corrupt memory here */
|
||||
GHOST_ASSERT(fd >= 0 && fd < FD_SETSIZE, "X");
|
||||
|
||||
if (flags & GWL_IOR_READ) {
|
||||
FD_ZERO(&rfdset);
|
||||
FD_SET(fd, &rfdset);
|
||||
rfdp = &rfdset;
|
||||
}
|
||||
if (flags & GWL_IOR_WRITE) {
|
||||
FD_ZERO(&wfdset);
|
||||
FD_SET(fd, &wfdset);
|
||||
wfdp = &wfdset;
|
||||
}
|
||||
|
||||
if (timeout_ms >= 0) {
|
||||
tv.tv_sec = timeout_ms / 1000;
|
||||
tv.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
tvp = &tv;
|
||||
}
|
||||
|
||||
result = select(fd + 1, rfdp, wfdp, nullptr, tvp);
|
||||
#endif /* !HAVE_POLL */
|
||||
} while (result < 0 && errno == EINTR && !(flags & GWL_IOR_NO_RETRY));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int ghost_wl_display_event_pump(struct wl_display *wl_display)
|
||||
{
|
||||
/* Based on SDL's `Wayland_PumpEvents`. */
|
||||
int err;
|
||||
if (wl_display_prepare_read(wl_display) == 0) {
|
||||
/* Use #GWL_IOR_NO_RETRY to ensure #SIGINT will break us out of our wait. */
|
||||
if (file_descriptor_is_io_ready(
|
||||
wl_display_get_fd(wl_display), GWL_IOR_READ | GWL_IOR_NO_RETRY, 0) > 0) {
|
||||
err = wl_display_read_events(wl_display);
|
||||
}
|
||||
else {
|
||||
wl_display_cancel_read(wl_display);
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = wl_display_dispatch_pending(wl_display);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static size_t ghost_wl_shm_format_as_size(enum wl_shm_format format)
|
||||
{
|
||||
switch (format) {
|
||||
|
@ -5169,7 +5252,7 @@ bool GHOST_SystemWayland::processEvents(bool waitForEvent)
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (wl_display_roundtrip(display_->wl_display) == -1) {
|
||||
if (ghost_wl_display_event_pump(display_->wl_display) == -1) {
|
||||
ghost_wl_display_report_error(display_->wl_display);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,11 @@ extern "C" {
|
|||
WAYLAND_DYNLOAD_FN(wl_display_connect)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_disconnect)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_dispatch)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_dispatch_pending)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_get_fd)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_prepare_read)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_read_events)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_cancel_read)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_roundtrip)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_flush)
|
||||
WAYLAND_DYNLOAD_FN(wl_display_get_error)
|
||||
|
@ -68,6 +73,11 @@ struct WaylandDynload_Client {
|
|||
void WL_DYN_FN(wl_display_disconnect)(struct wl_display *display);
|
||||
int WL_DYN_FN(wl_display_dispatch)(struct wl_display *display);
|
||||
int WL_DYN_FN(wl_display_roundtrip)(struct wl_display *display);
|
||||
int WL_DYN_FN(wl_display_dispatch_pending)(struct wl_display *display);
|
||||
int WL_DYN_FN(wl_display_get_fd)(struct wl_display *display);
|
||||
int WL_DYN_FN(wl_display_prepare_read)(struct wl_display *display);
|
||||
int WL_DYN_FN(wl_display_read_events)(struct wl_display *display);
|
||||
void WL_DYN_FN(wl_display_cancel_read)(struct wl_display *display);
|
||||
int WL_DYN_FN(wl_display_flush)(struct wl_display *display);
|
||||
int WL_DYN_FN(wl_display_get_error)(struct wl_display *display);
|
||||
void WL_DYN_FN(wl_log_set_handler_client)(wl_log_func_t);
|
||||
|
@ -103,6 +113,15 @@ struct WaylandDynload_Client {
|
|||
# define wl_display_disconnect(...) \
|
||||
(*wayland_dynload_client.wl_display_disconnect)(__VA_ARGS__)
|
||||
# define wl_display_dispatch(...) (*wayland_dynload_client.wl_display_dispatch)(__VA_ARGS__)
|
||||
# define wl_display_dispatch_pending(...) \
|
||||
(*wayland_dynload_client.wl_display_dispatch)(__VA_ARGS__)
|
||||
# define wl_display_get_fd(...) (*wayland_dynload_client.wl_display_get_fd)(__VA_ARGS__)
|
||||
# define wl_display_prepare_read(...) \
|
||||
(*wayland_dynload_client.wl_display_prepare_read)(__VA_ARGS__)
|
||||
# define wl_display_read_events(...) \
|
||||
(*wayland_dynload_client.wl_display_read_events)(__VA_ARGS__)
|
||||
# define wl_display_cancel_read(...) \
|
||||
(*wayland_dynload_client.wl_display_cancel_read)(__VA_ARGS__)
|
||||
# define wl_display_roundtrip(...) (*wayland_dynload_client.wl_display_roundtrip)(__VA_ARGS__)
|
||||
# define wl_display_flush(...) (*wayland_dynload_client.wl_display_flush)(__VA_ARGS__)
|
||||
# define wl_display_get_error(...) (*wayland_dynload_client.wl_display_get_error)(__VA_ARGS__)
|
||||
|
|
Loading…
Reference in New Issue