Skip to content

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

Closed

Description

@jseifeddine

Symptom

An RDP session that should fill the browser window leaves a strip of bare page down the right-hand edge, about the width of a scrollbar. Seen in Safari fullscreen on a 1710x1112 MacBook display, but it is not browser specific.

Numbers from the session page console:

[innerWidth, innerHeight, display.getWidth(), display.getHeight(), display.getScale()]
[1710, 960, 1696, 960, 1]

Cause

The client asks for 1710x960. Windows honours the height but rounds the width down to a multiple of 16 when the session runs without the Graphics Pipeline (the entry has GFX off, which is rustguac's default), so the framebuffer comes back 1696 wide. scaleDisplay() in client.html then fits with a uniform min(availW / dw, availH / dh): the height already matches, the scale stays at 1, and the missing 14px shows as a strip. guacd's own rounding is only to a multiple of 4 on the initial connect and to even widths on resize (guac_rdp_disp_set_size), so the rest is the server's doing.

Turning GFX on for the entry avoids it, since RDPGFX accepts any even width, but the client should not show a strip over a 0.8% shortfall whatever the server does.

Fix

In scaleDisplay(), after the uniform fit, stretch the display element by the remaining fraction on each axis when that fraction is at most 2.5%, and divide the same factors out of pointer coordinates before sendMouseState. A gap bigger than that is a real aspect mismatch (fixed-resolution server, no resize support) and keeps the letterbox as today. Multi-monitor pop-outs are untouched.

Folded into #255.

Activity

  1. added a commit that references this issue on Oct 10, 2026
    27f9b18
  2. pletch commented on Oct 11, 2026

    @pletch
    Contributor

    The rounding is coming from rustguac's own guacd, not from Windows. patches/007-rdp-disp-mod16.patch changes guac_rdp_disp_set_size to round both dimensions down to a multiple of 16 (stock guacamole-server rounds to even, which is probably the source being read here). 1710x960 → 1696x960 is exactly that: 960 is already a multiple of 16, and 1710 isn't. Turning GFX on shouldn't avoid it either, since resizes go through the display channel with or without GFX. If you're seeing a difference with GFX on, I'd be curious what guacd logs for the requested size.

    I added that patch deliberately. When the negotiated size isn't mod-16, the H.264 encoder pads to whole macroblocks, the padding contaminates the bottom chroma row, and once that is scaled it shows as a saturated green band along the edge. The patch comment already names the cost: "up to 15px of unused canvas margin". This issue is that cost made visible, so please don't take it as a reason to relax the rounding. The green band is the worse of the two.

    On the proposed fix: because every RDP session whose window isn't mod-16 will have up to 15px of margin, a ≤2.5% stretch would apply to almost every RDP session, not an edge case. A non-integer CSS scale resamples the whole picture, which softens single-pixel text across the entire screen. It also breaks pixel-exact rendering when the framebuffer is requested at device pixels on HiDPI displays (1 framebuffer pixel per physical pixel), where even a small stretch is measurably soft. Trading a 14px strip for blur everywhere seems like the wrong trade.

    Two alternatives that keep it sharp:

    • Centre the framebuffer and give the margin the display's background colour (7px a side on dark rather than 14px of bare page on one side), or
    • Only apply the fill when the display is already being resampled (display.getScale() * devicePixelRatio !== 1), so it never costs sharpness on a pixel-exact session.

    The pointer maths in the current patch is right, by the way: Guacamole.Position uses offsetLeft, which ignores transforms, so dividing out fillX/fillY is correct.

  3. added 2 commits that reference this issue on Oct 12, 2026
    53cfe8b
    7bfe0a3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions