diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 697cd8388c7..d5dc8c2a783 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -906,11 +906,11 @@ bool DisplayServerWayland::window_is_focused(WindowID p_window_id) const { } bool DisplayServerWayland::window_can_draw(DisplayServer::WindowID p_window_id) const { - return !suspended; + return suspend_state == SuspendState::NONE; } bool DisplayServerWayland::can_any_window_draw() const { - return !suspended; + return suspend_state == SuspendState::NONE; } void DisplayServerWayland::window_set_ime_active(const bool p_active, DisplayServer::WindowID p_window_id) { @@ -1132,16 +1132,21 @@ void DisplayServerWayland::try_suspend() { if (emulate_vsync) { bool frame = wayland_thread.wait_frame_suspend_ms(1000); if (!frame) { - suspended = true; - } - } else { - if (wayland_thread.is_suspended()) { - suspended = true; + suspend_state = SuspendState::TIMEOUT; } } - if (suspended) { - DEBUG_LOG_WAYLAND("Window suspended."); + // If we suspended by capability, we'll know with this check. We must do this + // after `wait_frame_suspend_ms` as it progressively dispatches the event queue + // during the "timeout". + if (wayland_thread.is_suspended()) { + suspend_state = SuspendState::CAPABILITY; + } + + if (suspend_state == SuspendState::TIMEOUT) { + DEBUG_LOG_WAYLAND("Suspending. Reason: timeout."); + } else if (suspend_state == SuspendState::CAPABILITY) { + DEBUG_LOG_WAYLAND("Suspending. Reason: capability."); } } @@ -1226,7 +1231,7 @@ void DisplayServerWayland::process_events() { wayland_thread.keyboard_echo_keys(); - if (!suspended) { + if (suspend_state == SuspendState::NONE) { // Due to the way legacy suspension works, we have to treat low processor // usage mode very differently than the regular one. if (OS::get_singleton()->is_in_low_processor_usage_mode()) { @@ -1250,9 +1255,23 @@ void DisplayServerWayland::process_events() { } else { try_suspend(); } - } else if (!wayland_thread.is_suspended() || wayland_thread.get_reset_frame()) { - // At last, a sign of life! We're no longer suspended. - suspended = false; + } else { + if (suspend_state == SuspendState::CAPABILITY) { + // If we suspended by capability we can assume that it will be reset when + // the compositor wants us to repaint. + if (!wayland_thread.is_suspended()) { + suspend_state = SuspendState::NONE; + DEBUG_LOG_WAYLAND("Unsuspending from capability."); + } + } else if (suspend_state == SuspendState::TIMEOUT) { + // Certain compositors might not report the "suspended" wm_capability flag. + // Because of this we'll wake up at the next frame event, indicating the + // desire for the compositor to let us repaint. + if (wayland_thread.get_reset_frame()) { + suspend_state = SuspendState::NONE; + DEBUG_LOG_WAYLAND("Unsuspending from timeout."); + } + } } #ifdef DBUS_ENABLED diff --git a/platform/linuxbsd/wayland/display_server_wayland.h b/platform/linuxbsd/wayland/display_server_wayland.h index beab5a83128..8c3bac9c7e3 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.h +++ b/platform/linuxbsd/wayland/display_server_wayland.h @@ -105,6 +105,12 @@ class DisplayServerWayland : public DisplayServer { Point2i hotspot; }; + enum class SuspendState { + NONE, // Unsuspended. + TIMEOUT, // Legacy fallback. + CAPABILITY, // New "suspended" wm_capability flag. + }; + CursorShape cursor_shape = CURSOR_ARROW; DisplayServer::MouseMode mouse_mode = DisplayServer::MOUSE_MODE_VISIBLE; @@ -118,7 +124,7 @@ class DisplayServerWayland : public DisplayServer { String ime_text; Vector2i ime_selection; - bool suspended = false; + SuspendState suspend_state = SuspendState::NONE; bool emulate_vsync = false; String rendering_driver;