From 1551973258cf44643a10150be7ed7641b3b5d70f Mon Sep 17 00:00:00 2001 From: Jonah Graham Date: Sat, 22 Nov 2025 11:10:35 -0500 Subject: [PATCH] [Edge] Cancel the timer from running when we are done with it Each use of a timer creates a User Object in Windows, and once we have stopped waiting for our desired event we don't need the cancellation tracking anymore. If there are lots of calls to processOSMessagesUntil, such as repeated browser.setText within the MAXIMUM_OPERATION_TIME (5 second) window, we can end up with a huge growth in the number of User Objects, leading to potential `SWTError: No more handles` errors elsewhere in the client code. Fixes https://github.com/eclipse-platform/eclipse.platform.swt/issues/2806 --- .../win32/org/eclipse/swt/browser/Edge.java | 4 +++- .../junit/Test_org_eclipse_swt_browser_Browser.java | 13 +++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/Edge.java b/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/Edge.java index 4243495a64..edf1de646f 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/Edge.java +++ b/bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/Edge.java @@ -551,7 +551,8 @@ private static void processOSMessagesUntil(Supplier condition, Consumer MSG msg = new MSG(); AtomicBoolean timeoutOccurred = new AtomicBoolean(); // The timer call also wakes up the display to avoid being stuck in display.sleep() - display.timerExec((int) MAXIMUM_OPERATION_TIME.toMillis(), () -> timeoutOccurred.set(true)); + Runnable runnable = () -> timeoutOccurred.set(true); + display.timerExec((int) MAXIMUM_OPERATION_TIME.toMillis(), runnable); while (!display.isDisposed() && !condition.get() && !timeoutOccurred.get()) { if (OS.PeekMessage(msg, 0, 0, 0, OS.PM_NOREMOVE | OS.PM_QS_POSTMESSAGE)) { display.readAndDispatch(); @@ -559,6 +560,7 @@ private static void processOSMessagesUntil(Supplier condition, Consumer display.sleep(); } } + display.timerExec(-1, runnable); if (!condition.get()) { timeoutHandler.accept(createTimeOutException()); } diff --git a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java index e70662fe84..595b49efc1 100644 --- a/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java +++ b/tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java @@ -76,6 +76,7 @@ import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Shell; @@ -2981,6 +2982,18 @@ public void test_TabTraversalOutOfBrowser() { assertTrue(text.isFocusControl()); } +// Regression test for https://github.com/eclipse-platform/eclipse.platform.swt/issues/2806 +@Test +public void test_TimerRegression_Issue2806() { + for (int i = 0; i < 10000; i++) { + browser.setText("Iteration " + i); + new BrowserFunction(browser, "name"); + } + new Composite(shell, SWT.NONE); + processUiEvents(); + +} + /* custom */ /** * Wait for passTest to return true. Timeout otherwise.