Skip to content

client: keep a pixel-exact RDP picture crisp and centre the mod-16 margin - #267

Closed
jseifeddine wants to merge 9 commits into
sol1:mainfrom
jseifeddine:fix/rdp-framebuffer-fit
Closed

jseifeddine wants to merge 9 commits into
sol1:mainfrom
jseifeddine:fix/rdp-framebuffer-fit

Conversation

@jseifeddine

Copy link
Copy Markdown
Contributor

Stacked PR 4 of 18 — builds on #266 (fix/tables-1710px). Merge in order from #264. This PR's own change is the compare on the fork: jseifeddine/rustguac@fix/tables-1710px...fix/rdp-framebuffer-fit. The Files tab here includes the PRs below it until they merge into main.

Fixes #251.

Per @pletch's review on #251: the fill stretch applies only when the picture is already being resampled (scale × devicePixelRatio ≠ 1), where it costs no sharpness; a pixel-exact session is never stretched and the framebuffer is centred so the mod-16 margin splits evenly in the dark background instead of showing as a bare strip. offsetLeft includes the centring margins and ignores the transform, so the pointer maths is unchanged.

Testing

  • Automated: node tests/client-fit.mjs pins the rules (never stretch pixel-exact, fill ≤2.5% when resampled, letterbox above, never shrink). Runs in the CI e2e job.
  • Manual: Windows RDP with GFX off, 1710×1112 fullscreen: no strip, text crisp, pointer lands where it is clicked.

The Content-Security-Policy had no img-src, so default-src 'self'
governed images and refused the data: URIs the Guacamole client draws
every tile from on browsers without WebCodecs ImageDecoder. Safari and
Firefox rendered SSH and RDP sessions black with only rect fills and the
cursor cell showing; Chrome decodes straight from the stream and never
fetches a URL, which hid it. The same directive blocks the remote mouse
cursor (cursor: url(data:...)) and blob: image URLs.

Move the policy into a documented constant, add img-src 'self' data:
blob:, and add a unit test that fails if img-src loses either source.
Document the proxy-side header replacement for releases up to v1.10.5.

Fixes sol1#249
… input after the transition

With fullscreen-on-connect, the first mousedown after CONNECTED is the
browser's fullscreen gesture, but Guacamole.Mouse forwarded it to guacd
as well, and the transition that followed swallowed its release. guacd
was left with the button held and the terminal selected text on every
pointer move; the same with a key press as the gesture.

Stop the gesture event before the display's handlers see it, and on
entering fullscreen release everything explicitly: keyboard.reset() and
a mouse state with no buttons at the last pointer position, so a release
lost for any other reason during the transition cannot stick either.

Fixes sol1#256
The 18px table with 20px cell padding and a separate cell each for
edit, clone and delete overran the main column by ~300px on a 1710px
MacBook display, cutting "delete" off the right edge.

Put the three admin actions in one cell, and add a max-width: 1800px
breakpoint on the connections page: 20px page padding, 240-280px
sidebar, 16px cells with tighter padding, 14px headers, a 110px
Connect button and a smaller folder title. The icon-only "open in new
window" button keeps its compact size. Nothing is hidden; at 1710px the
table fits with about 250px to spare.

Fixes sol1#252
The 18px tables with 20px cell padding ran past the right edge on a
1710px MacBook display, the recording link cut off. Same treatment as
the connections table: 16px cells with tighter padding, 14px headers,
actions kept on one line. Nothing is hidden.

Part of sol1#254
The 1800px breakpoint set a tighter page gutter on the connections page
only, so switching to Sessions or any other tab snapped the content
sideways. Move it to rustguac.css so every page moves together.

Part of sol1#254
A browser test harness under tests/e2e: serve.mjs serves the real static
tree over HTTP and lib/api.mjs answers /api/* from a small fixture address
book, recording every request the page makes, so the shipped pages run
against data the test controls without Vault, guacd or a session. CI gains
an e2e job that installs Chromium and runs the suite.

The first spec pins sol1#252: at 1710px the connections, recordings and reports
tables fit inside the viewport and nothing scrolls sideways.
Windows RDP without GFX rounds the requested width down to a multiple
of 16, so a 1710-wide window gets a 1696-wide desktop. The uniform fit
in scaleDisplay() then keeps the scale at 1 (the height matches) and
the missing 14px shows as a strip of bare page down the right edge.

After the uniform fit, stretch the display element by the remaining
fraction on each axis when it is at most 2.5%, and divide the same
factors out of pointer coordinates before sendMouseState. A larger gap
is a real aspect mismatch and keeps the letterbox. Multi-monitor
pop-outs reset the fill.

Fixes sol1#251
…rgin

Stretching the display to fill a mod-16 shortfall costs sharpness when the
picture is already drawn one framebuffer pixel per physical pixel, and
nearly every RDP session hits the rounding. So the fill now applies only
when the picture is already being resampled (scale x devicePixelRatio != 1),
where it costs nothing; a pixel-exact session is never stretched, and the
framebuffer is centred in the available area so the small margin is split
evenly in the dark background instead of showing as a bare strip down one
edge. offsetLeft includes the centring margins and ignores the fill
transform, so the pointer maths that divides out fillX/fillY is unchanged.

Fixes sol1#251
tests/client-fit.mjs lifts applyFill() out of client.html and runs it on a
stand-in element: a pixel-exact picture is never stretched, a resampled one
fills a gap of at most 2.5% per axis, a larger gap keeps the letterbox, and
nothing is ever shrunk through the fill. Run in the CI e2e job.
@davekempe

Copy link
Copy Markdown
Member

Merged into main as 53cfe8b, 7bfe0a3 and 026b949 (the test), thanks Jad. The version Tim signed off on in #255. One change on our side: the comments now say the rounding comes from our patch 007, not Windows, so nobody relaxes it later. The fit test runs in our existing CI job instead of the e2e job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RDP: strip of bare page on the right when Windows rounds the width down (GFX off)

2 participants