Skip to content

feat: pass the exact display scale to FreeRDP - #960

Open
oraturk75 wants to merge 1 commit into
winapps-org:mainfrom
oraturk75:scale-desktop-exact
Open

feat: pass the exact display scale to FreeRDP#960
oraturk75 wants to merge 1 commit into
winapps-org:mainfrom
oraturk75:scale-desktop-exact

Conversation

@oraturk75

Copy link
Copy Markdown

What this changes

RDP_SCALE is rounded to 100, 140 or 180 before being passed to FreeRDP, on the premise recorded in waFixScale that "FreeRDP only supports '/scale' values of 100, 140 or 180."

That is true of /scale, but not of /scale-desktop, which accepts any integer from 100 to 500. So a user asking for 125 silently gets 140.

This passes the configured value through as /scale-desktop and derives the device scale separately as /scale-device.

Why both factors

/scale sets DesktopScaleFactor and DeviceScaleFactor together. Switching to /scale-desktop alone would have quietly reset the device factor to 100 and made Store/UWP apps worse — apps/powerbi-store ships in this repo, so that is a real regression rather than a hypothetical one.

The device factor really is limited: FreeRDP's /scale-device accepts only 100, 140 or 180, and that mirrors the constraint on deviceScaleFactor in the client core data. So it still has to be sent, and it still has to be approximated — the existing rounding logic is reused for that rather than deleted. At RDP_SCALE=125 the result is desktop 125, device 140: deliberately mismatched, and better than rounding both to 140.

The removed notification

#148 added a notify-send warning that the value was unsupported. That warning is now wrong: the desktop value is honoured exactly, and only the device value is approximated. Since waFixScale runs from waLoadConfig, it also fired on every launch to report something the user could not act on. Replaced with a debug message that says only the device value was approximated.

Validation

The old rounding incidentally sanitised RDP_SCALE. Passing the value through raw means a non-integer or an out-of-range number reaches /scale-desktop, which rejects the command — surfacing as a launch that silently does nothing.

So the value is now validated: a non-integer is fatal, and a value outside 100–500 is clamped with a warning rather than rejected, so an existing misconfigured setup keeps working instead of breaking.

Related to #825, which asks for automatic per-monitor detection. This does not implement that, but it removes the rounding that would have discarded a detected fractional value.

Testing

Against Windows 11 Pro, FreeRDP 3.30.0, X11.

Windows honours non-standard desktopScaleFactor. Measured with a fixed-size dialog (winver) as a RemoteApp, /scale-device held at 100, reading the server-reported window geometry:

/scale-desktop reported geometry
100 460x423
125 575x521
150 691x621

Width scales exactly (460 → 575 → 691). Height carries a constant ~31px of window chrome; once that is accounted for, both axes predict the 150% point within 2px.

Full-desktop mode confirmed separately via a DPI-aware probe in the guest: 96 / 120 / 144 DPI at 100 / 125 / 150.

Also exercised: 125 → desktop 125, device 140; 600 → clamped to 500, device 180; 250 → desktop 250, device 180; a non-integer → fatal in both bin/winapps and setup.sh. A Store app was launched at mismatched factors. All four call sites in bin/winapps and both in setup.sh were run.

pre-commit run passes on all changed files.

Not tested: the Wayland path. bin/winapps selects sdl-freerdp3 for the full desktop session on Wayland, and this was tested on X11 only.

AI Assistance Disclosure

This change was mostly written by Claude Opus 5 under my supervision. Every change was reviewed before it was committed, and the test results are real runs against my own Windows 11 VM.

RDP_SCALE was rounded to 100, 140 or 180 on the premise that FreeRDP
only supports those values. That is true of /scale, but not of
/scale-desktop, which accepts any integer from 100 to 500. A user
asking for 125 silently got 140.

Pass the configured value through as /scale-desktop, and derive the
device scale separately as /scale-device. Both factors still get set:
/scale set them together, so switching to /scale-desktop alone would
have quietly reset DeviceScaleFactor to 100 and made Store apps worse.
The device factor genuinely is limited to 100, 140 and 180, so it is
still approximated - but only it, and the debug output now says so
rather than claiming the whole value was unsupported.

The per-launch notify-send is gone. waFixScale runs on every
configuration load, so it fired on every launch to report something the
user cannot act on.

RDP_SCALE is now validated, since the old rounding incidentally
sanitised it. A non-integer is fatal; a value outside 100-500 is clamped
with a warning rather than rejected, so an existing misconfigured setup
keeps working instead of failing to launch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Tony Dursun <oraturk75@gmail.com>
@oskardotglobal

Copy link
Copy Markdown
Member

So if I understand this correctly, if I set a scale of 158, this will scale the desktop accordingly, but RAILS will still be scaled to 140? That seems unintuitive. Maybe we should just have a seperate scale for desktop and RAILS?

@oskardotglobal oskardotglobal added triage Further information is requested ai Created using assistance of LLMs labels Aug 27, 2026
@oraturk75

Copy link
Copy Markdown
Author

Good question, and the README wording is what made it ambiguous. Sorry about that.

/scale-device is not the RemoteApp scale. Per MS-RDPBCGR 2.2.1.3.2 these are two distinct fields with different allowed ranges, sent together and each validated against the other: desktopScaleFactor is valid from 100 to 500, and deviceScaleFactor is restricted to 100, 140 or 180. /scale-desktop is what sizes the session, and that includes RemoteApp windows.

I measured this before writing the patch. Winver under RemoteApp, with /scale-device pinned at 100 and only /scale-desktop varied, using the window geometry the server reports:

/scale-desktop window width ratio
100 460 x 423 1.000
125 575 x 521 1.250
150 691 x 621 1.502

Linear fits on both axes are within 2 px across the three points, with a fixed ~31 px offset on height that is window chrome. So at RDP_SCALE=158 the RemoteApp windows scale at 158, not 140.

The old /scale set both fields. Sending only /scale-desktop would silently change deviceScaleFactor from the rounded value WinApps currently sends to FreeRDP's default of 100, so this patch preserves the existing device-factor behavior. That field is the only value being approximated.

I will clarify the README. Does this address your concern, or would you still prefer separate user control of deviceScaleFactor?

@oskardotglobal

oskardotglobal commented Aug 29, 2026

Copy link
Copy Markdown
Member

I think a seperate config option for the desktop scale defaulting to the value of RDP_SCALE would be preferred, with RDP_SCALE controlling RemoteApp scaling.

Also, please do not copy-paste the answer of the LLM as the response to my question. As per our policy, we accept AI-generated code, but this is just bad etiquette and doesn't really support your claim of having reviewed the changes by hand.

@oraturk75

Copy link
Copy Markdown
Author

Hey, I thought more about this PR work and #825, which inspired part of it, and I believe something got lost in the transit. There is no reason why I should not include automatic detection of the primary monitor scale (on Cinnamon/X11) from #825 as part of this PR, since it completes the scaling work already here. I do not have a multi-monitor setup, so I cannot reproduce nor properly test those issues and will leave that part of #825 for someone else.

I will add the separate full-desktop scale option per your request. Also; I have decided to expand this PR to include automatic scale detection. Of course, manual scale settings will always override automatic detection. Is that okay with you?

PS: Sorry about earlier posts, didn't mean any disrespect.

@oskardotglobal

Copy link
Copy Markdown
Member

Sure, automatic scale detection sounds super useful! Also, multi-monitor scaling is a non-trivial issue and FreeRDPs multi-monitor capabilities are dubious anyways, so focusing on single-monitor scale detection seems like the right choice

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

Labels

ai Created using assistance of LLMs triage Further information is requested

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants