From 3a9abc638f6f357ffe9369a10776efaf22b30b25 Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Thu, 17 Sep 2026 12:24:54 +0200 Subject: [PATCH] [Win32] Do not constrain Shell size to owner shell bounds fitInParentBounds() clamps a control's requested bounds to fit inside its parent's client area, evening out off-by-one rounding errors from point/pixel conversions. Shell.setSize() (inherited from Control, not overridden) also routed through this method, treating the Shell's owner (Control.parent) as if it were a geometric container. An owned Shell is a top-level window positioned independently of its owner on screen; it is not laid out inside the owner's rectangle. The clamp could therefore spuriously shrink a Shell's requested height or width by one pixel whenever the owner's and the owned shell's on-screen positions happened to coincide within the off-by-one tolerance window, causing sporadic Test_org_eclipse_swt_widgets_Shell.test_setSizeII / test_setSizeLorg_eclipse_swt_graphics_Point failures unrelated to DPI autoscaling. Add a deterministic regression test that explicitly positions the owned shell to hit the off-by-one tolerance window on both axes. The test runs on all platforms; assertions wait via SwtTestUtil.processEvents() for the requested size to be reported, since GTK reports Shell bounds asynchronously via the window manager. Fixes https://github.com/eclipse-platform/eclipse.platform.swt/issues/3597 Assisted-by: Claude Sonnet 4.6 --- .../org/eclipse/swt/widgets/Control.java | 5 +++- .../Test_org_eclipse_swt_widgets_Shell.java | 27 +++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java index a162c1ce6ea..48c50564a48 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Control.java @@ -3353,7 +3353,10 @@ public void setBounds (Rectangle rect) { * Thus, reduce the control size in case it would not fit anyway */ private void fitInParentBounds(Rectangle boundsInPixels, int zoom) { - if (parent == null) { + if (parent == null || this instanceof Shell) { + // A Shell is a geometric top-level element and must not be fit into any + // logical parent's bounds — even if it has another Shell set as parent + // (which denotes an owner relationship, not geometric containment). return; } Rectangle parentBoundsInPixels = parent.getBoundsInPixels(); diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java index bebbe450e8d..b660734626e 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Shell.java @@ -821,6 +821,33 @@ public void test_setSizeLorg_eclipse_swt_graphics_Point() { } } +// See https://github.com/eclipse-platform/eclipse.platform.swt/issues/3597 +@Test +public void test_setSize_ownedShellNotConstrainedByOwnerBounds() throws InterruptedException { + shell.setSize(500, 500); + shell.open(); + + int ownerHeight = shell.getSize().y; + int ownerWidth = shell.getSize().x; + testShell.open(); + + // Make shell vertically exceed parent shell bounds + int requestedHeight = 100; + testShell.setLocation(0, ownerHeight - requestedHeight + 1); + testShell.setSize(200, requestedHeight); + SwtTestUtil.processEvents(10000, () -> testShell.getSize().y == requestedHeight); + assertEquals(requestedHeight, testShell.getSize().y, + "Owned Shell height must not be constrained by owner Shell bounds"); + + // Make shell horizontally exceed parent shell bounds + int requestedWidth = 100; + testShell.setLocation(ownerWidth - requestedWidth + 1, 0); + testShell.setSize(requestedWidth, 200); + SwtTestUtil.processEvents(10000, () -> testShell.getSize().x == requestedWidth); + assertEquals(requestedWidth, testShell.getSize().x, + "Owned Shell width must not be constrained by owner Shell bounds"); +} + private void assertShellProperlySized(Shell shell, Point expectedSize) { int tolerance = shell.getZoom() != 100 ? 1 : 0; Point actualSize = shell.getSize();