diff --git a/src/workspaces/officerdev/src/apps/Desktop/DesktopView.tsx b/src/workspaces/officerdev/src/apps/Desktop/DesktopView.tsx index 91eea6ea..537fe22e 100644 --- a/src/workspaces/officerdev/src/apps/Desktop/DesktopView.tsx +++ b/src/workspaces/officerdev/src/apps/Desktop/DesktopView.tsx @@ -140,14 +140,18 @@ export const DesktopView = ({ className, style }: DesktopViewProps) => { credentials: { password }, }); - // resizeSession WITHOUT scaleViewport. They are alternatives, not complements: resizeSession asks - // the server to become the container's size, scaleViewport scales whatever the server sends to fit. - // Xvnc implements RandR SetDesktopSize, so the session really does become the container size and - // there is nothing left to scale. With both enabled any gap between the size requested and the size - // granted leaves a fractional scale that pointer coordinates are mapped through — which is how the - // cursor ended up offset from where you clicked. One strategy, 1:1 pixels, no coordinate maths. + // BOTH. They are not alternatives — scaling is the fallback that covers the gap between resize + // events, and more importantly it is what keeps the coordinate maths self-consistent. + // + // noVNC maps a click as (clientX - canvasRect.left) / display._scale. Only scaleViewport's + // autoscale() sets the canvas's displayed size and _scale TOGETHER, so the two cannot disagree. + // Turning it off pins _scale at 1 while the canvas keeps being displayed at some other size, and + // nothing reconciles them: measured here, pointing a quarter of the way across the desktop landed + // at 51%, and pointing at the middle saturated at the right-hand edge. A clean factor of two. + // Clicks near the right and bottom edges still appeared to work, because doubling an already-large + // coordinate clamps back onto the edge it was aimed at. rfb.resizeSession = true; - rfb.scaleViewport = false; + rfb.scaleViewport = true; rfb.focusOnClick = true; // noVNC hides the browser's own cursor over the canvas and draws the REMOTE cursor in its place. // Until the server sends a cursor shape its image is RFB.cursors.none — so nothing is drawn, the