From 3e621219f12e9168b152140d927d672f7877b379 Mon Sep 17 00:00:00 2001 From: Keith Smith Date: Mon, 14 Sep 2026 21:57:08 -0600 Subject: [PATCH] RDP: fix resize corruption by proactively resizing the local GDI buffer update->DesktopResize (the only place gdi_resize() was called) only fires during a full Deactivation-Reactivation sequence or a GFX ResetGraphics PDU, neither of which our Display Control channel resize path (SendMonitorLayout, MS-RDPEDISP) triggers. The client's own display buffer was left stuck at its initial-connect size for the rest of the session, and FreeRDP's surface-bits handling silently drops updates outside those stale bounds -- producing the missing/misplaced taskbar and stale composited-looking content. sendDisplayResize now calls gdi_resize() itself right after a successful SendMonitorLayout, rather than waiting on a callback that structurally never fires for this channel/codec configuration. Fixes #18. Co-Authored-By: Claude Sonnet 5 --- src/rdp_session_backend.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/rdp_session_backend.cpp b/src/rdp_session_backend.cpp index f9a8fcc..4784259 100644 --- a/src/rdp_session_backend.cpp +++ b/src/rdp_session_backend.cpp @@ -1933,6 +1933,30 @@ bool RdpSessionBackend::sendDisplayResize(rdp_freerdp* instance, int width, int m_lastResizeHeight = height; m_lastResizeScale = static_cast(scaleValue); + // The Display Control channel (MS-RDPEDISP) has no server + // acknowledgment PDU, and real hosts apply the new resolution + // without a Deactivation-Reactivation sequence — so + // update->DesktopResize (which only fires for that sequence, or + // for the GFX/Progressive pipeline we don't use) never runs for + // a channel-driven resize. Without a matching gdi_resize() call, + // gdi->width/height stay at the old size, and FreeRDP's own + // surface-bits handling (intersect_rect in gdi.c) then silently + // *drops* any update reaching outside those stale bounds — + // which is what produced the missing/misplaced taskbar and + // stale composited-looking content: this call is the fix, not + // just a best-effort nudge. + if (instance->context->gdi != nullptr + && gdi_resize(instance->context->gdi, static_cast(width), + static_cast(height))) { + emit remoteDesktopSizeChanged(width, height); + } else if (instance->context->gdi != nullptr) { + emit eventLogged(QStringLiteral( + "RDP warning: local resize to %1x%2 failed; display may show stale content " + "until the next full repaint.") + .arg(width) + .arg(height)); + } + // Best-effort nudge: some hosts don't fully repaint their own // desktop after a resolution change (observed: taskbar missing // until something else forces a redraw). Explicitly asking for