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 e6efbc73db..74d490c4c3 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 @@ -133,6 +133,7 @@ public class Shell extends Decorations { boolean ignoreFocusOut, ignoreFocusIn; boolean ignoreFocusOutAfterGrab, grabbedFocus; Region originalRegion; + long gdkSurfaceNotifyStateHandler, gdkSurfaceComputeSizeHandler; static final int MAXIMUM_TRIM = 128; static final int BORDER = 3; @@ -965,8 +966,8 @@ void hookEvents () { // Replaced "window-state-event" with GdkSurface "notify::state", pass shellHandle as user_data GTK.gtk_widget_realize(shellHandle); long gdkSurface = gtk_widget_get_surface (shellHandle); - OS.g_signal_connect (gdkSurface, OS.notify_state, display.notifyProc, shellHandle); - OS.g_signal_connect (gdkSurface, OS.compute_size, display.computeSizeProc, shellHandle); + gdkSurfaceNotifyStateHandler = OS.g_signal_connect (gdkSurface, OS.notify_state, display.notifyProc, shellHandle); + gdkSurfaceComputeSizeHandler = OS.g_signal_connect (gdkSurface, OS.compute_size, display.computeSizeProc, shellHandle); OS.g_signal_connect(shellHandle, OS.notify_default_height, display.notifyProc, Widget.NOTIFY_DEFAULT_HEIGHT); OS.g_signal_connect(shellHandle, OS.notify_default_width, display.notifyProc, Widget.NOTIFY_DEFAULT_WIDTH); OS.g_signal_connect(shellHandle, OS.notify_maximized, display.notifyProc, Widget.NOTIFY_MAXIMIZED); @@ -3431,6 +3432,24 @@ void releaseWidget () { if (group != 0) OS.g_object_unref (group); group = modalGroup = 0; lastActive = null; + // Disconnect GdkSurface signal handlers for GTK4 + if (GTK.GTK4 && shellHandle != 0 && GTK.gtk_widget_get_realized(shellHandle)) { + try { + long gdkSurface = GTK4.gtk_native_get_surface(GTK4.gtk_widget_get_native(shellHandle)); + if (gdkSurface != 0) { + if (gdkSurfaceNotifyStateHandler != 0) { + OS.g_signal_handler_disconnect(gdkSurface, gdkSurfaceNotifyStateHandler); + gdkSurfaceNotifyStateHandler = 0; + } + if (gdkSurfaceComputeSizeHandler != 0) { + OS.g_signal_handler_disconnect(gdkSurface, gdkSurfaceComputeSizeHandler); + gdkSurfaceComputeSizeHandler = 0; + } + } + } catch (Throwable t) { + // Ignore errors during cleanup - widget may already be partially destroyed + } + } if (regionToDispose != null) { regionToDispose.dispose(); } 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 dccc258988..86eba82771 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 @@ -1004,6 +1004,22 @@ public void test_Issue450_NoShellActivateOnSetFocus() { } } +@Test +public void test_createAndDisposeMultipleShells() { + // Test for GTK4 crash when creating and disposing many shells + // See https://github.com/eclipse-platform/eclipse.platform.swt/issues/XXXX + Display display = shell.getDisplay(); + for (int i = 0; i < 100; i++) { + Shell testShell = new Shell(display); + testShell.open(); + while (display.readAndDispatch()) { + // Process events + } + testShell.close(); + testShell.dispose(); + } +} + @Override public void test_setLocationLorg_eclipse_swt_graphics_Point() { //Setting location for Windows is not supported in GTK4