From 5ba89ae74d7559bb76cf0f1b5e4247e5369ad089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 1 Aug 2026 23:20:36 +0000 Subject: [PATCH] =?UTF-8?q?desktop:=20restore=20scaleViewport=20=E2=80=94?= =?UTF-8?q?=20disabling=20it=20doubled=20every=20pointer=20coordinate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reverts the scaleViewport=false half of 69c750d. That change was wrong and it caused a worse bug than the one it was aimed at. noVNC maps a click as (clientX - canvasRect.left) / display._scale. autoscale(), which only runs when scaleViewport is enabled, sets the canvas's displayed size and _scale in the same call, so the two are consistent by construction. With scaleViewport off, _scale is pinned at 1 while the canvas continues to be displayed at some other size and nothing reconciles them. Measured on the owner's session against a 1109x715 desktop: pointing a quarter of the way across registered at x=575 (51%), and pointing at the middle saturated at x=1108, the right-hand edge. A clean factor of two in both axes. 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 — which is why the panel clock and the dock stayed clickable while the middle of the screen did not. My reasoning for the original change — that resizeSession and scaleViewport are alternatives — was simply wrong. They are complementary: resize matches the session to the container, scaling covers the interval before the server honours it, and scaling is also what keeps the coordinate maths honest. showDotCursor stays: the invisible pointer was a real and separate defect. Co-Authored-By: Claude Opus 5 (1M context) --- .../src/apps/Desktop/DesktopView.tsx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) 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