Fix #141846: Successive calls to change the cursor exits on Wayland

Calling wm.progress_update() from Python in a loop would exit
under Wayland.

Resolve by calling wl_display_dispatch after changing the cursor.
This commit is contained in:
Campbell Barton
2025-07-13 04:56:39 +00:00
parent 481776a105
commit 98a949f997

View File

@@ -56,6 +56,22 @@
/* Logging, use `ghost.wl.*` prefix. */
#include "CLG_log.h"
/**
* Note that for almost all cases a call to `wl_display_dispatch` is *not* needed.
* Without the dispatch though, calls to set the cursor while the event loop is
* not being processed causes a resource allocation failure - disconnecting the
* WAYLAND compositor (effectively crashing).
* While this only happens when many calls are made, that's exactly what happens in the
* case of the "progress" feature which uses the cursor to display a number.
* See: #141846.
*
* Observed behavior when changing cursors without a dispatch:
* - Eventually exits with an error on all compositors tested (KDE/GNOME/WLROOTS based).
* - Won't re-display at all (on KDE 6.4).
* Note that this could be a bug in KDE as it works in GNOME & WLROOTS based compositors.
*/
#define USE_CURSOR_IMMEDIATE_DISPATCH
/**
* LIBDECOR support committing a window-configuration in the main-thread that was
* handled in a non-main-thread.
@@ -2242,10 +2258,18 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCursorShape(GHOST_TStandardCursor s
ok_test = system_->cursor_shape_set(m_cursorShape);
}
if (ok_test == GHOST_kFailure) {
/* For the cursor to display when the event queue isn't being handled. */
wl_display_flush(system_->wl_display_get());
wl_display *display = system_->wl_display_get();
#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
if (ok == GHOST_kSuccess || ok_test == GHOST_kSuccess) {
wl_display_flush(display);
wl_display_dispatch(display);
}
else
#endif /* USE_CURSOR_IMMEDIATE_DISPATCH */
if (ok_test == GHOST_kFailure) {
/* For the cursor to display when the event queue isn't being handled. */
wl_display_flush(display);
}
}
else {
/* Set later when activating the window. */
@@ -2291,8 +2315,12 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCustomCursorShape(
ok_test = system_->cursor_shape_set(m_cursorShape);
}
if (ok_test == GHOST_kSuccess) {
wl_display *display = system_->wl_display_get();
/* For the cursor to display when the event queue isn't being handled. */
wl_display_flush(system_->wl_display_get());
wl_display_flush(display);
#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
wl_display_dispatch(display);
#endif
}
}
else {
@@ -2405,8 +2433,12 @@ GHOST_TSuccess GHOST_WindowWayland::setWindowCursorVisibility(bool visible)
#endif
const GHOST_TSuccess ok = system_->cursor_visibility_set(visible);
if (ok == GHOST_kSuccess) {
wl_display *display = system_->wl_display_get();
/* For the cursor to display when the event queue isn't being handled. */
wl_display_flush(system_->wl_display_get());
wl_display_flush(display);
#ifdef USE_CURSOR_IMMEDIATE_DISPATCH
wl_display_dispatch(display);
#endif
}
return ok;
}