From f0004a6170b09958e4be14ac08aca7c11a7b366f Mon Sep 17 00:00:00 2001 From: Heiko Klare Date: Thu, 3 Sep 2026 08:23:31 +0200 Subject: [PATCH] [Win32] Release DPI change callback also on failure The processing of a zoom change can be scheduled asynchronously via a native timer, for which a callback is allocated and released again once the processing has been performed. If the processing fails, the callback is currently not released. Callback slots are a limited resource shared by the whole application. Once they are exhausted, allocating a callback fails, which makes the scheduling of the zoom change processing fall back to performing it synchronously and can break other functionality relying on callbacks as well. The callback is therefore released independently of the outcome of the processing. Assisted-by: Claude Opus 5 --- .../win32/org/eclipse/swt/widgets/Control.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) 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 8aac323cd12..f516fe8b4fe 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 @@ -6062,10 +6062,15 @@ private DPIChangeProcessingCallback(Control control, Runnable dpiChangeProcessin // Has to have TIMERPROC signature, see https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-timerproc Callback callback = new Callback(this, "run", void.class, new Type[] { int.class, int.class, int.class, int.class} ); this.operation = () -> { - if (!control.isDisposed()) { - dpiChangeProcessing.run(); + try { + if (!control.isDisposed()) { + dpiChangeProcessing.run(); + } + } finally { + // The callback must be released in any case, as callback slots are a + // limited resource and leaking them makes further scheduling fail + callback.dispose(); } - callback.dispose(); }; this.address = callback.getAddress(); }