Fix RDP session drop/flicker: stop re-parenting Guacamole display (#45)
Symptom: desktop flickers in for a moment then goes blank while the tab still says "connected"; guacd logs "User is not responding" and the client reconnects in a loop. Root cause: the multi-session view moved each session's display element between DOM nodes on tab switch (host.innerHTML='' + appendChild). Detaching a guacamole-common-js display from the DOM stalls its sync loop, so the client stops echoing guacd's sync instructions and guacd drops it as unresponsive. Proven out-of-band: a raw guacd client that echoes sync held a connection for 30s/116 syncs with no drop, while the browser dropped within seconds. Fix: mount each session's container into the display host ONCE and never move it; toggle visibility (display:none) to switch tabs so every session's display stays in the DOM and its sync loop keeps running. Containers are absolutely positioned in a relative host; close still removes the container. Co-authored-by: Samuel James <ssamjame@amazon.com> Co-authored-by: Kiro <noreply@kiro.dev>
This commit is contained in:
parent
a7fbbabeb2
commit
58a46553d9
1 changed files with 17 additions and 15 deletions
|
|
@ -64,7 +64,13 @@ export default function RemoteDesktop() {
|
|||
setActiveSessionId(sessionId)
|
||||
|
||||
const container = document.createElement('div')
|
||||
container.className = 'h-full w-full overflow-auto'
|
||||
container.className = 'absolute inset-0 overflow-auto'
|
||||
container.style.display = 'none'
|
||||
// Mount the container into the display host ONCE and never move it again —
|
||||
// re-parenting the Guacamole display between DOM nodes breaks its sync loop,
|
||||
// which makes guacd drop the user as "not responding". We toggle visibility
|
||||
// instead (see the activation effect below).
|
||||
displayHostRef.current?.appendChild(container)
|
||||
|
||||
const token = getToken()
|
||||
const proto = window.location.protocol === 'https:' ? 'wss' : 'ws'
|
||||
|
|
@ -105,20 +111,16 @@ export default function RemoteDesktop() {
|
|||
})
|
||||
}
|
||||
|
||||
// Show only the active session's display element; keep the rest mounted off-DOM so
|
||||
// background sessions stay connected while their tab isn't focused.
|
||||
// Show only the active session's display; keep all others mounted but hidden so
|
||||
// their sessions stay connected AND their sync loop keeps running (do NOT move
|
||||
// them out of the DOM — that breaks Guacamole's sync and guacd drops them).
|
||||
useEffect(() => {
|
||||
const host = displayHostRef.current
|
||||
if (!host) return
|
||||
host.innerHTML = ''
|
||||
const active = activeSessionId ? handlesRef.current.get(activeSessionId) : null
|
||||
if (active) {
|
||||
host.appendChild(active.container)
|
||||
// The display may have received its size while off-DOM (zero-sized), which
|
||||
// leaves the canvas unscaled / invisible — re-fit now that it's visible.
|
||||
fitDisplay(active, host)
|
||||
}
|
||||
}, [activeSessionId])
|
||||
handlesRef.current.forEach((handle, id) => {
|
||||
const visible = id === activeSessionId
|
||||
handle.container.style.display = visible ? 'block' : 'none'
|
||||
if (visible) fitDisplay(handle, displayHostRef.current)
|
||||
})
|
||||
}, [activeSessionId, sessions])
|
||||
|
||||
// Keep the active session scaled to the panel as the window/panel resizes.
|
||||
useEffect(() => {
|
||||
|
|
@ -216,7 +218,7 @@ export default function RemoteDesktop() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
<div ref={displayHostRef} className="flex-1 overflow-auto" />
|
||||
<div ref={displayHostRef} className="relative flex-1 overflow-hidden" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue