From d98462245fd6df1c8b8e9106959e4286660803e7 Mon Sep 17 00:00:00 2001 From: Lars Vogel Date: Tue, 25 Aug 2026 19:45:09 +0200 Subject: [PATCH] [GTK] Do not pass a negative size to gtk_widget_size_allocate A Shell with a container border (SWT.TOOL | SWT.ON_TOP, as used by the JFace information controls) that is asked for a height of 0 ends up with a client box of -1: setBounds clamps the height to 1 and resizeBounds then subtracts the 2 pixel border. GTK rejects the negative allocation, so the shell keeps its natural size while its content box is never laid out. That shows up as a correctly sized but completely empty popup, together with Gtk-CRITICAL: gtk_widget_get_preferred_width_for_height: assertion 'height >= 0' failed Gtk-WARNING : gtk_widget_size_allocate(): attempt to allocate widget with width 226 and height -1 Clamp the box size to zero so a degenerate request stays degenerate instead of corrupting the layout. Contributes to https://github.com/eclipse-platform/eclipse.platform.swt/issues/3539 --- .../gtk/org/eclipse/swt/widgets/Shell.java | 6 ++++-- .../Test_org_eclipse_swt_widgets_Shell.java | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java index c55f99be603..7957f7e99d9 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java +++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Shell.java @@ -2361,8 +2361,10 @@ void resizeBounds (int width, int height, boolean notify) { GDK.gdk_window_resize (enableWindow, width, height); } } - int boxWidth = width - 2*border; - int boxHeight = height - 2*border; + // GTK rejects negative allocations; a shell smaller than its own border must not + // leak a negative size into gtk_widget_size_allocate(). + int boxWidth = Math.max (0, width - 2*border); + int boxHeight = Math.max (0, height - 2*border); if ((style & SWT.RESIZE) == 0) { GTK.gtk_widget_set_size_request (vboxHandle, boxWidth, boxHeight); } 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 d16f1e47ae1..bebbe450e8d 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 @@ -1054,4 +1054,24 @@ public void test_setLocationII() { } super.test_setLocationII(); } + +@Test +public void test_degenerateSizeDoesNotExpandShell() { + // A bordered popup asked for a height of 0 used to be allocated -1, which GTK rejects, + // so it fell back to its natural size with its content never laid out. See issue 3539. + // GTK4 backs these shells with a GtkPopover, which never went through that box maths + // and enforces a minimum height of its own. + assumeTrue(SwtTestUtil.isGTK && !SwtTestUtil.isGTK4()); + Shell popup = new Shell(shell, SWT.TOOL | SWT.ON_TOP); + popup.setLayout(new FillLayout()); + Button child = new Button(popup, SWT.PUSH); + child.setText("some content that is clearly taller than two pixels"); + popup.setSize(228, 0); + popup.setVisible(true); + SwtTestUtil.processEvents(); + Rectangle clientArea = popup.getClientArea(); + popup.dispose(); + assertTrue(clientArea.height >= 0, "negative client area: " + clientArea); + assertTrue(clientArea.height <= 2, "shell expanded to its natural size: " + clientArea); +} }