Skip to content

[Windows] Per-window-auto-scaling broke computerSize(wHint, SWT.DEFAULT) #3119

Open

Description

@tmssngr

Describe the bug
The per-window-auto-scaling enabled in c35c568 broke the ScrolledComposite behavior (for displaying scrollbars only if needed) used for displaying dialogs in our applications.

To Reproduce
Snippet:

import org.eclipse.swt.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class ScrolledCompositeTest {

	public static void main(String[] args) {
		final Display display = new Display();

		final Shell shell = new Shell(display);
		final FillLayout fillLayout = new FillLayout();
		fillLayout.marginWidth = fillLayout.marginHeight = 20;
		shell.setLayout(fillLayout);

		final ScrolledComposite sc = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL);
		sc.setExpandHorizontal(true);
		sc.setExpandVertical(true);

		final Label label = new Label(sc, SWT.WRAP);
		label.setText("This is a longer line, but not very long.\nanother line");
		sc.setContent(label);

		final Point size = label.computeSize(SWT.DEFAULT, SWT.DEFAULT);
		sc.setMinSize(size);
		sc.addListener(SWT.Resize, unused -> {
			final Rectangle r = sc.getClientArea();
			final Point size1 = label.computeSize(r.width, SWT.DEFAULT);
			sc.setMinSize(size1);
		});

		shell.setSize(300, 100);
		shell.open();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch()) {
				display.sleep();
			}
		}

		display.dispose();
	}
}

Run it with SWT at commit 577b1d6 and you will get
Image
You can resize the window and if it is to small to show the text, a vertical scrollbar will occur:
Image

Now try with SWT at commit c35c568 or newer and you will get
Image
You can resize the window and sometimes the horizontal scrollbar is shown, sometimes not.

Expected behavior
The ScrolledComposite should work as with commit 577b1d6 or earlier.

Environment:

  1. Select the platform(s) on which the behavior is seen:
    • All OS
    • Windows
    • Linux
    • macOS
  1. Additional OS info (e.g. OS version, Linux Desktop, etc)
    Windows 11 25H2

  2. JRE/JDK version

Workaround (or) Additional context
No workarounds known.

Activity

  1. HeikoKlare commented on Mar 5, 2026

    @HeikoKlare
    Contributor

    Expected behavior
    The ScrolledComposite should work as with commit 577b1d6 or earlier.

    The behavior is unchanged when at 100% zoom. For fractional zooms, the expected behavior is probably impossible to achieve with the integer-based precision of SWT's logical coordinate system but requires a rewrite and API exchange for SWT coordinates.

    It might be possible to improve specific calculations/roundings to achieve better compatibility here, but it might not be that easy and, in particular, the time might be better invested into finding a proper UI definition than aligning sizes with each other in a custom way. There are layouts available for achieving the intended behavior which take care of fitting controls into each other. In case there are also issues when defining an according UI with layouts, I would rather invest time into fixing that.

  2. tmssngr commented on Mar 5, 2026

    @tmssngr
    ContributorAuthor

    Just a guess without having looked at the implementation: maybe computeSize should always round up so it definitely has enough space?

  3. tmssngr commented on Mar 6, 2026

    @tmssngr
    ContributorAuthor

    IMHO the problem is that after scaling up and down the label.computeSize(r.width, SWT.DEFAULT) will return one pixel larger than r.width which is not expected. Are there any cases where for width or height != SWT.DEFAULT a different size is returned? Otherwise I would consider to change Control.computeSize:

    public Point computeSize (int wHint, int hHint, boolean changed){
    	checkWidget ();
    	int zoom = computeBoundsZoom();
    	//We should never return a size that is to small, RoundingMode.UP ensures we at worst case report
    	//a size that is a bit too large by half a point
    	return Win32DPIUtils.pixelToPointAsSufficientlyLargeSize(computeSizeInPixels(new Point(wHint, hHint), zoom, changed), zoom);
    }

    to

    public Point computeSize (int wHint, int hHint, boolean changed){
    	checkWidget ();
    	int zoom = computeBoundsZoom();
    	//We should never return a size that is to small, RoundingMode.UP ensures we at worst case report
    	//a size that is a bit too large by half a point
    	final Point size = Win32DPIUtils.pixelToPointAsSufficientlyLargeSize(computeSizeInPixels(new Point(wHint, hHint), zoom, changed), zoom);
    	if (wHint != SWT.DEFAULT) size.x = wHint;
    	if (hHint != SWT.DEFAULT) size.y = hHint;
    	return size;
    }
  4. changed the title [-][Windows] Per-window-auto-scaling broke ScrolledComposite[/-] [+][Windows] Per-window-auto-scaling broke computerSize(wHint, SWT.DEFAULT)[/+] on Mar 6, 2026
  5. HeikoKlare commented on Mar 6, 2026

    @HeikoKlare
    Contributor

    Just a guess without having looked at the implementation: maybe computeSize should always round up so it definitely has enough space?

    That's exactly what it does:

    return Win32DPIUtils.pixelToPointAsSufficientlyLargeSize(computeSizeInPixels(new Point(wHint, hHint), zoom, changed), zoom);

    There are multiple issues summing up here. One is that the label.computeSize() call rounds up resulting in a width that is one point to large. But that's not the root cause, as it's fed with a value retrieved from getClientArea() that is already imprecise (too large).

    getClientArea() is rounded value. The problem with getClientArea() is that there is no "proper" way of rounding that value. You have two use cases from consumer side requiring different rounding:

    • The consumer wants to fit something in the client area (like done here), then you would like to rather have a rounded-down value.
    • The consumer wants to fill the whole client area (e.g., for refresh the drawing), then you would like to rather have a rounded-up value.

    An additional problem is that when converting rectangles between point and pixels, it's values are already rounded (so there is no Rectangle.OfFloat result with a rounding method that might be adapted). So as a consumer of `getClientArea(), you have no chance of reconstruction the actual/precise values. Maybe that's something that could be improved, but we need to be aware as we had quite some issues with not rounding or inconsistently rounding a rectangle's values due to the variety of its use cases.

    IMHO the problem is that after scaling up and down the label.computeSize(r.width, SWT.DEFAULT) will return one pixel larger than r.width which is not expected. Are there any cases where for width or height != SWT.DEFAULT a different size is returned?

    As mentioned above, that's not the root cause of the issue. And yes, there are of course cases in which the resulting width/height can be a different than the passed size. That's why those values are called "hints". The control can make use of them in whatever way it wants to compute the actual size. Otherwise there would not even be any need of calling computeSize() when you have the desired values at hand anyway.

  6. tmssngr commented on Mar 6, 2026

    @tmssngr
    ContributorAuthor

    I think, more and more I better understand that the rounding introduces problems, but duplicating all size/position methods for points and pixels is no alternative.

    Otherwise there would not even be any need of calling computeSize() when you have the desired values at hand anyway.

    Here we want to know the height for a given width because of text wrapping.

  7. HeikoKlare commented on Mar 6, 2026

    @HeikoKlare
    Contributor

    duplicating all size/position methods for points and pixels is no alternative.

    Yes, in particular because SWT is intended to abstract from pixel values and relieve consumers from the necessity to deal with zooms. It's just that for fractional scaling it's difficult to achieve a proper behavior in every case due to the logical position/size values being integer-based. What we did at some places is to carry precise values in Point/Rectangle instances that are passed around under the hood. In this case, we might want to have getClientArea() yield a Rectangle that carries precise values, but the calculations on top of that would have to process those precise values as well. And you would need to be able to pass precise values to a computeSize() calculation, which is currently not possible due to the method accepting two integer values. Resolving all of that leads to something like in the following commit, which would fix most of the reported issue (but of course not in an acceptable way):
    HeikoKlare@a39d48b

    Here we want to know the height for a given width because of text wrapping.

    I see. What might also work here is to take the original client area width into account when setting the minimum size of the scrolled composite. I.e., in the listener, instead of ...

    sc.setMinSize(size1);

    ... you may do:

    sc.setMinSize(Math.min(size1.x, r.width), size1.y);

    For me, that seems to solve the issue.

  8. added
    WindowsHappens on Windows OS
    HiDPIIssues related to High resolution monitors
    on May 6, 2026
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

    HiDPIIssues related to High resolution monitorsWindowsHappens on Windows OS

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions