|
18 | 18 | import java.awt.Canvas; |
19 | 19 | import java.awt.event.*; |
20 | 20 | import java.lang.reflect.*; |
| 21 | +import java.util.concurrent.*; |
| 22 | +import java.util.concurrent.atomic.*; |
| 23 | +import java.util.function.*; |
21 | 24 |
|
22 | 25 | import org.eclipse.swt.*; |
23 | 26 | import org.eclipse.swt.graphics.Rectangle; |
|
37 | 40 | */ |
38 | 41 | public class SWT_AWT { |
39 | 42 |
|
| 43 | + private static final int AWT_WAITING_TIME_FOR_SWT_THREAD = 5_000; // in milliseconds |
| 44 | + |
| 45 | + private static final int SWT_THREAD_BLOCK_LIMIT = 200; // in milliseconds |
| 46 | + |
40 | 47 | /** |
41 | 48 | * The name of the embedded Frame class. The default class name |
42 | 49 | * for the platform will be used if <code>null</code>. |
@@ -246,22 +253,63 @@ public void handleEvent (Event e) { |
246 | 253 | case SWT.FocusIn: |
247 | 254 | EventQueue.invokeLater(() -> { |
248 | 255 | if (frame.isActive()) return; |
249 | | - try { |
250 | | - synthesizeWindowActivation (frame, Boolean.TRUE); |
251 | | - } catch (Throwable e1) {e1.printStackTrace();} |
| 256 | + synchronizedExecution(() -> parent.isFocusControl(),() -> { synthesizeWindowActivation (frame, Boolean.TRUE);} ); |
252 | 257 | }); |
253 | 258 | break; |
254 | 259 | case SWT.Deactivate: |
255 | 260 | case SWT.FocusOut: |
256 | 261 | EventQueue.invokeLater(() -> { |
257 | 262 | if (!frame.isActive()) return; |
258 | | - try { |
259 | | - synthesizeWindowActivation (frame, Boolean.FALSE); |
260 | | - } catch (Throwable e1) {e1.printStackTrace();} |
| 263 | + synchronizedExecution(() -> !parent.isFocusControl(),() -> { synthesizeWindowActivation (frame, Boolean.FALSE);} ); |
261 | 264 | }); |
262 | 265 | break; |
263 | 266 | } |
264 | 267 | } |
| 268 | + |
| 269 | + /** |
| 270 | + * |
| 271 | + * It must be made sure, that the parent composite is in the same focus state like the AWT frame. |
| 272 | + * This is not sure, because AWT will be executed asynchronous, in the meantime the SWT main thread can continue and change the state again. |
| 273 | + * |
| 274 | + * Example: in eclipse the perspective changes cause many FocusIn,FocusOut events and if there are multiple SWT_AWT frames, |
| 275 | + * these can break the embedded AWT feature. |
| 276 | + * |
| 277 | + * 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). |
| 278 | + * 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 |
| 279 | + * the state there does not change. |
| 280 | + * |
| 281 | + * In case the AWT part freezes or fails, then the SWT thread continues after the short time period. |
| 282 | + * |
| 283 | + * @param swtExec executed check in swt main thread |
| 284 | + * @param awtExec action to be executed in awt thread |
| 285 | + */ |
| 286 | + private void synchronizedExecution(Supplier< Boolean> swtExec, Runnable awtExec ) { |
| 287 | + |
| 288 | + try { |
| 289 | + AtomicBoolean swtResult = new AtomicBoolean(); |
| 290 | + final CountDownLatch swtThreadStart = new CountDownLatch(1); |
| 291 | + final CountDownLatch awtThreadEnd = new CountDownLatch(1); |
| 292 | + |
| 293 | + Display.getDefault().asyncExec(() -> { |
| 294 | + swtResult.set(swtExec.get()); |
| 295 | + swtThreadStart.countDown(); |
| 296 | + try { |
| 297 | + awtThreadEnd.await(SWT_THREAD_BLOCK_LIMIT, TimeUnit.MILLISECONDS); |
| 298 | + } catch (InterruptedException e1) { |
| 299 | + e1.printStackTrace(); |
| 300 | + } |
| 301 | + }); |
| 302 | + swtThreadStart.await(AWT_WAITING_TIME_FOR_SWT_THREAD, TimeUnit.MILLISECONDS); |
| 303 | + |
| 304 | + if(swtResult.get()) { |
| 305 | + awtExec.run(); |
| 306 | + } |
| 307 | + awtThreadEnd.countDown(); |
| 308 | + |
| 309 | + } catch (Throwable e1) {e1.printStackTrace();} |
| 310 | + |
| 311 | + |
| 312 | + } |
265 | 313 | }; |
266 | 314 |
|
267 | 315 | parent.addListener (SWT.FocusIn, listener); |
|
0 commit comments