Fix blank RDP screen in multi-session view: scale display + fit on activate (#44)
The multi-session RemoteDesktop tabs (05e78f0) appended the Guacamole display
into an off-DOM container before connecting, and never called display.scale().
Frames arrived while the canvas was detached/zero-sized, so the desktop rendered
but painted to an invisible area — connected-but-blank.
Fix: track the display per session, fit/scale it to the visible panel when a
session becomes active, on the display's own onresize, and on window resize.
Verified the VM/xrdp/guacd side streams frames fine (13-36 img frames in direct
guacd tests); this was purely the client-side mount/scale regression.
Co-authored-by: Samuel James <ssamjame@amazon.com>
Co-authored-by: Kiro <noreply@kiro.dev>
This commit is contained in:
parent
6c1f167f15
commit
a7fbbabeb2
1 changed files with 39 additions and 3 deletions
|
|
@ -17,6 +17,19 @@ interface Session {
|
|||
interface SessionHandle {
|
||||
client: any
|
||||
container: HTMLDivElement
|
||||
display: any
|
||||
}
|
||||
|
||||
// Scale the Guacamole display to fit its visible container. The display canvas
|
||||
// renders at the remote resolution; without this it can paint to a 0-sized /
|
||||
// unscaled area (blank screen) when the element wasn't in the live DOM at connect.
|
||||
function fitDisplay(handle: SessionHandle | null | undefined, host: HTMLElement | null) {
|
||||
if (!handle || !host) return
|
||||
const w = handle.display.getWidth()
|
||||
const h = handle.display.getHeight()
|
||||
if (!w || !h) return
|
||||
const scale = Math.min(host.clientWidth / w, host.clientHeight / h, 1) || 1
|
||||
handle.display.scale(scale)
|
||||
}
|
||||
|
||||
export default function RemoteDesktop() {
|
||||
|
|
@ -25,6 +38,8 @@ export default function RemoteDesktop() {
|
|||
const [activeSessionId, setActiveSessionId] = useState<string | null>(null)
|
||||
const displayHostRef = useRef<HTMLDivElement>(null)
|
||||
const handlesRef = useRef<Map<string, SessionHandle>>(new Map())
|
||||
const activeSessionIdRef = useRef<string | null>(null)
|
||||
activeSessionIdRef.current = activeSessionId
|
||||
|
||||
useEffect(() => {
|
||||
api.listIntegrations().then(({ integrations }) => {
|
||||
|
|
@ -57,7 +72,8 @@ export default function RemoteDesktop() {
|
|||
// so the tunnel URL itself must not already contain one.
|
||||
const tunnel = new Guacamole.WebSocketTunnel(`${proto}://${window.location.host}/api/guacamole`)
|
||||
const client = new Guacamole.Client(tunnel)
|
||||
handlesRef.current.set(sessionId, { client, container })
|
||||
const display = client.getDisplay()
|
||||
handlesRef.current.set(sessionId, { client, container, display })
|
||||
|
||||
client.onerror = (err: { message?: string }) => {
|
||||
patchSession(sessionId, { status: 'error', errorMessage: err?.message ?? 'Connection failed' })
|
||||
|
|
@ -65,8 +81,13 @@ export default function RemoteDesktop() {
|
|||
client.onstatechange = (state: number) => {
|
||||
if (state === 3) patchSession(sessionId, { status: 'connected' })
|
||||
}
|
||||
// Re-fit whenever the remote desktop reports a new size, but only while this
|
||||
// session is the visible one.
|
||||
display.onresize = () => {
|
||||
if (activeSessionIdRef.current === sessionId) fitDisplay(handlesRef.current.get(sessionId), displayHostRef.current)
|
||||
}
|
||||
|
||||
container.appendChild(client.getDisplay().getElement())
|
||||
container.appendChild(display.getElement())
|
||||
client.connect(`token=${encodeURIComponent(token ?? '')}&integrationId=${host.id}`)
|
||||
}
|
||||
|
||||
|
|
@ -91,9 +112,24 @@ export default function RemoteDesktop() {
|
|||
if (!host) return
|
||||
host.innerHTML = ''
|
||||
const active = activeSessionId ? handlesRef.current.get(activeSessionId) : null
|
||||
if (active) host.appendChild(active.container)
|
||||
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])
|
||||
|
||||
// Keep the active session scaled to the panel as the window/panel resizes.
|
||||
useEffect(() => {
|
||||
const onResize = () => {
|
||||
const active = activeSessionIdRef.current ? handlesRef.current.get(activeSessionIdRef.current) : null
|
||||
fitDisplay(active, displayHostRef.current)
|
||||
}
|
||||
window.addEventListener('resize', onResize)
|
||||
return () => window.removeEventListener('resize', onResize)
|
||||
}, [])
|
||||
|
||||
const activeSession = sessions.find((s) => s.sessionId === activeSessionId)
|
||||
|
||||
return (
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue