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 {
|
interface SessionHandle {
|
||||||
client: any
|
client: any
|
||||||
container: HTMLDivElement
|
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() {
|
export default function RemoteDesktop() {
|
||||||
|
|
@ -25,6 +38,8 @@ export default function RemoteDesktop() {
|
||||||
const [activeSessionId, setActiveSessionId] = useState<string | null>(null)
|
const [activeSessionId, setActiveSessionId] = useState<string | null>(null)
|
||||||
const displayHostRef = useRef<HTMLDivElement>(null)
|
const displayHostRef = useRef<HTMLDivElement>(null)
|
||||||
const handlesRef = useRef<Map<string, SessionHandle>>(new Map())
|
const handlesRef = useRef<Map<string, SessionHandle>>(new Map())
|
||||||
|
const activeSessionIdRef = useRef<string | null>(null)
|
||||||
|
activeSessionIdRef.current = activeSessionId
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api.listIntegrations().then(({ integrations }) => {
|
api.listIntegrations().then(({ integrations }) => {
|
||||||
|
|
@ -57,7 +72,8 @@ export default function RemoteDesktop() {
|
||||||
// so the tunnel URL itself must not already contain one.
|
// so the tunnel URL itself must not already contain one.
|
||||||
const tunnel = new Guacamole.WebSocketTunnel(`${proto}://${window.location.host}/api/guacamole`)
|
const tunnel = new Guacamole.WebSocketTunnel(`${proto}://${window.location.host}/api/guacamole`)
|
||||||
const client = new Guacamole.Client(tunnel)
|
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 }) => {
|
client.onerror = (err: { message?: string }) => {
|
||||||
patchSession(sessionId, { status: 'error', errorMessage: err?.message ?? 'Connection failed' })
|
patchSession(sessionId, { status: 'error', errorMessage: err?.message ?? 'Connection failed' })
|
||||||
|
|
@ -65,8 +81,13 @@ export default function RemoteDesktop() {
|
||||||
client.onstatechange = (state: number) => {
|
client.onstatechange = (state: number) => {
|
||||||
if (state === 3) patchSession(sessionId, { status: 'connected' })
|
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}`)
|
client.connect(`token=${encodeURIComponent(token ?? '')}&integrationId=${host.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -91,9 +112,24 @@ export default function RemoteDesktop() {
|
||||||
if (!host) return
|
if (!host) return
|
||||||
host.innerHTML = ''
|
host.innerHTML = ''
|
||||||
const active = activeSessionId ? handlesRef.current.get(activeSessionId) : null
|
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])
|
}, [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)
|
const activeSession = sessions.find((s) => s.sessionId === activeSessionId)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue