diff --git a/common/rfb/EncodeManager.cxx b/common/rfb/EncodeManager.cxx index 01cb5a1e1..c3361693f 100644 --- a/common/rfb/EncodeManager.cxx +++ b/common/rfb/EncodeManager.cxx @@ -365,8 +365,21 @@ void EncodeManager::writeLosslessRefresh(const Region& req, const ScreenSet &la const RenderedCursor* renderedCursor, size_t maxUpdateSize) { - if (videoDetected || video_mode_available) + if (videoDetected || video_mode_available) { + // In video mode there's no lossless refresh to send, but pending + // pseudo-encodings (cursor shape, LED state, etc.) must still be + // flushed — otherwise the cursor shape lags whenever the desktop + // is idle (e.g. user hovering a window edge to resize). Without + // this, writeFramebufferUpdate() reaches us via writeDataUpdate's + // "ui.is_empty() but needFakeUpdate()" branch and we early-return, + // never emitting the FBU that would carry the pseudo-rects. + if (conn->writer()->needFakeUpdate()) { + int nRects = conn->cp.supportsLastRect ? 0xFFFF : 0; + conn->writer()->writeFramebufferUpdateStart(nRects); + conn->writer()->writeFramebufferUpdateEnd(); + } return; + } doUpdate(false, getLosslessRefresh(req, maxUpdateSize), Region(), Point(), std::vector(), layout, pb, renderedCursor);