From 9ed30891f2a358089ccd33c5f2eca9b74165115b Mon Sep 17 00:00:00 2001 From: Denis Ungemach Date: Fri, 19 Dec 2025 14:13:00 +0100 Subject: [PATCH] [mac]SWT_AWT: synchronize the main thread and the awt thread --- .../cocoa/org/eclipse/swt/awt/SWT_AWT.java | 60 +++++++++++++++++-- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/bundles/org.eclipse.swt/Eclipse SWT AWT/cocoa/org/eclipse/swt/awt/SWT_AWT.java b/bundles/org.eclipse.swt/Eclipse SWT AWT/cocoa/org/eclipse/swt/awt/SWT_AWT.java index 6c474f7e4b6..58c1ee269d3 100644 --- a/bundles/org.eclipse.swt/Eclipse SWT AWT/cocoa/org/eclipse/swt/awt/SWT_AWT.java +++ b/bundles/org.eclipse.swt/Eclipse SWT AWT/cocoa/org/eclipse/swt/awt/SWT_AWT.java @@ -18,6 +18,9 @@ import java.awt.Canvas; import java.awt.event.*; import java.lang.reflect.*; +import java.util.concurrent.*; +import java.util.concurrent.atomic.*; +import java.util.function.*; import org.eclipse.swt.*; import org.eclipse.swt.graphics.Rectangle; @@ -37,6 +40,10 @@ */ public class SWT_AWT { + private static final int AWT_WAITING_TIME_FOR_SWT_THREAD = 5_000; // in milliseconds + + private static final int SWT_THREAD_BLOCK_LIMIT = 200; // in milliseconds + /** * The name of the embedded Frame class. The default class name * for the platform will be used if null. @@ -246,22 +253,63 @@ public void handleEvent (Event e) { case SWT.FocusIn: EventQueue.invokeLater(() -> { if (frame.isActive()) return; - try { - synthesizeWindowActivation (frame, Boolean.TRUE); - } catch (Throwable e1) {e1.printStackTrace();} + synchronizedExecution(() -> parent.isFocusControl(),() -> { synthesizeWindowActivation (frame, Boolean.TRUE);} ); }); break; case SWT.Deactivate: case SWT.FocusOut: EventQueue.invokeLater(() -> { if (!frame.isActive()) return; - try { - synthesizeWindowActivation (frame, Boolean.FALSE); - } catch (Throwable e1) {e1.printStackTrace();} + synchronizedExecution(() -> !parent.isFocusControl(),() -> { synthesizeWindowActivation (frame, Boolean.FALSE);} ); }); break; } } + + /** + * + * It must be made sure, that the parent composite is in the same focus state like the AWT frame. + * This is not sure, because AWT will be executed asynchronous, in the meantime the SWT main thread can continue and change the state again. + * + * Example: in eclipse the perspective changes cause many FocusIn,FocusOut events and if there are multiple SWT_AWT frames, + * these can break the embedded AWT feature. + * + * So in the SWT main thread the state of the parent will be checked and it will be blocked for a very short time (SWT_THREAD_BLOCK_LIMIT). + * In this time, we change the behaviour in the AWT thread to the right state and since we block the SWT main thread, we ensure, that + * the state there does not change. + * + * In case the AWT part freezes or fails, then the SWT thread continues after the short time period. + * + * @param swtExec executed check in swt main thread + * @param awtExec action to be executed in awt thread + */ + private void synchronizedExecution(Supplier< Boolean> swtExec, Runnable awtExec ) { + + try { + AtomicBoolean swtResult = new AtomicBoolean(); + final CountDownLatch swtThreadStart = new CountDownLatch(1); + final CountDownLatch awtThreadEnd = new CountDownLatch(1); + + Display.getDefault().asyncExec(() -> { + swtResult.set(swtExec.get()); + swtThreadStart.countDown(); + try { + awtThreadEnd.await(SWT_THREAD_BLOCK_LIMIT, TimeUnit.MILLISECONDS); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + }); + swtThreadStart.await(AWT_WAITING_TIME_FOR_SWT_THREAD, TimeUnit.MILLISECONDS); + + if(swtResult.get()) { + awtExec.run(); + } + awtThreadEnd.countDown(); + + } catch (Throwable e1) {e1.printStackTrace();} + + + } }; parent.addListener (SWT.FocusIn, listener);