2121import java .time .*;
2222import java .util .*;
2323import java .util .concurrent .*;
24+ import java .util .concurrent .atomic .*;
2425import java .util .function .*;
2526
2627import org .eclipse .swt .*;
@@ -58,6 +59,7 @@ class Edge extends WebBrowser {
5859 private static final String ABOUT_BLANK = "about:blank" ;
5960
6061 private static final int MAXIMUM_CREATION_RETRIES = 5 ;
62+ private static final Duration MAXIMUM_OPERATION_TIME = Duration .ofSeconds (5 );
6163
6264 private record WebViewEnvironment (ICoreWebView2Environment environment , ArrayList <Edge > instances ) {
6365 public WebViewEnvironment (ICoreWebView2Environment environment ) {
@@ -260,9 +262,7 @@ static int callAndWait(long[] ppv, ToIntFunction<IUnknown> callable) {
260262 phr [0 ] = callable .applyAsInt (completion );
261263 // "completion" callback may be called asynchronously,
262264 // so keep processing next OS message that may call it
263- while (phr [0 ] == COM .S_OK && ppv [0 ] == 0 ) {
264- processNextOSMessage ();
265- }
265+ processOSMessagesUntil (() -> phr [0 ] != COM .S_OK || ppv [0 ] != 0 );
266266 completion .Release ();
267267 return phr [0 ];
268268}
@@ -280,9 +280,7 @@ static int callAndWait(String[] pstr, ToIntFunction<IUnknown> callable) {
280280 phr [0 ] = callable .applyAsInt (completion );
281281 // "completion" callback may be called asynchronously,
282282 // so keep processing next OS message that may call it
283- while (phr [0 ] == COM .S_OK && pstr [0 ] == null ) {
284- processNextOSMessage ();
285- }
283+ processOSMessagesUntil (() -> phr [0 ] != COM .S_OK || pstr [0 ] != null );
286284 completion .Release ();
287285 return phr [0 ];
288286}
@@ -298,7 +296,7 @@ class WebViewWrapper {
298296
299297class WebViewProvider {
300298
301- private CompletableFuture <WebViewWrapper > webViewWrapperFuture = new CompletableFuture <>();
299+ private CompletableFuture <WebViewWrapper > webViewWrapperFuture = wakeDisplayAfterFuture ( new CompletableFuture <>() );
302300 private CompletableFuture <Void > lastWebViewTask = webViewWrapperFuture .thenRun (() -> {});;
303301
304302 ICoreWebView2 initializeWebView (ICoreWebView2Controller controller ) {
@@ -365,95 +363,91 @@ private ICoreWebView2_13 initializeWebView_13(ICoreWebView2 webView) {
365363 return null ;
366364 }
367365
368- ICoreWebView2 getWebView (boolean waitForPendingWebviewTasksToFinish ) {
366+ private WebViewWrapper getWebViewWrapper (boolean waitForPendingWebviewTasksToFinish ) {
369367 if (waitForPendingWebviewTasksToFinish ) {
370- waitForFutureToFinish (lastWebViewTask );
368+ processOSMessagesUntil (lastWebViewTask :: isDone );
371369 }
372- return webViewWrapperFuture .join ().webView ;
370+ return webViewWrapperFuture .join ();
371+ }
372+
373+ private WebViewWrapper getWebViewWrapper () {
374+ processOSMessagesUntil (webViewWrapperFuture ::isDone );
375+ return webViewWrapperFuture .join ();
376+ }
377+
378+ ICoreWebView2 getWebView (boolean waitForPendingWebviewTasksToFinish ) {
379+ return getWebViewWrapper (waitForPendingWebviewTasksToFinish ).webView ;
373380 }
374381
375382 ICoreWebView2_2 getWebView_2 (boolean waitForPendingWebviewTasksToFinish ) {
376- if (waitForPendingWebviewTasksToFinish ) {
377- waitForFutureToFinish (lastWebViewTask );
378- }
379- return webViewWrapperFuture .join ().webView_2 ;
383+ return getWebViewWrapper (waitForPendingWebviewTasksToFinish ).webView_2 ;
380384 }
381385
382386 boolean isWebView_2Available () {
383- waitForFutureToFinish (webViewWrapperFuture );
384- return webViewWrapperFuture .join ().webView_2 != null ;
387+ return getWebViewWrapper ().webView_2 != null ;
385388 }
386389
387390 ICoreWebView2_10 getWebView_10 (boolean waitForPendingWebviewTasksToFinish ) {
388- if (waitForPendingWebviewTasksToFinish ) {
389- waitForFutureToFinish (lastWebViewTask );
390- }
391- return webViewWrapperFuture .join ().webView_10 ;
391+ return getWebViewWrapper (waitForPendingWebviewTasksToFinish ).webView_10 ;
392392 }
393393
394394 boolean isWebView_10Available () {
395- waitForFutureToFinish (webViewWrapperFuture );
396- return webViewWrapperFuture .join ().webView_10 != null ;
395+ return getWebViewWrapper ().webView_10 != null ;
397396 }
398397
399398 ICoreWebView2_11 getWebView_11 (boolean waitForPendingWebviewTasksToFinish ) {
400- if (waitForPendingWebviewTasksToFinish ) {
401- waitForFutureToFinish (lastWebViewTask );
402- }
403- return webViewWrapperFuture .join ().webView_11 ;
399+ return getWebViewWrapper (waitForPendingWebviewTasksToFinish ).webView_11 ;
404400 }
405401
406402 boolean isWebView_11Available () {
407- waitForFutureToFinish (webViewWrapperFuture );
408- return webViewWrapperFuture .join ().webView_11 != null ;
403+ return getWebViewWrapper ().webView_11 != null ;
409404 }
410405
411406 ICoreWebView2_12 getWebView_12 (boolean waitForPendingWebviewTasksToFinish ) {
412- if (waitForPendingWebviewTasksToFinish ) {
413- waitForFutureToFinish (lastWebViewTask );
414- }
415- return webViewWrapperFuture .join ().webView_12 ;
407+ return getWebViewWrapper (waitForPendingWebviewTasksToFinish ).webView_12 ;
416408 }
417409
418410 boolean isWebView_12Available () {
419- waitForFutureToFinish (webViewWrapperFuture );
420- return webViewWrapperFuture .join ().webView_12 != null ;
411+ return getWebViewWrapper ().webView_12 != null ;
421412 }
422413
423414 ICoreWebView2_13 getWebView_13 (boolean waitForPendingWebviewTasksToFinish ) {
424- if (waitForPendingWebviewTasksToFinish ) {
425- waitForFutureToFinish (lastWebViewTask );
426- }
427- return webViewWrapperFuture .join ().webView_13 ;
415+ return getWebViewWrapper (waitForPendingWebviewTasksToFinish ).webView_13 ;
428416 }
429417
430418 boolean isWebView_13Available () {
431- waitForFutureToFinish (webViewWrapperFuture );
432- return webViewWrapperFuture .join ().webView_13 != null ;
419+ return getWebViewWrapper ().webView_13 != null ;
433420 }
434421
435422 /*
436423 * Schedule a given runnable in a queue to execute when the webView is free and
437424 * has finished all the pending tasks queued before it.
438425 */
439426 void scheduleWebViewTask (Runnable action ) {
440- lastWebViewTask = lastWebViewTask .thenRun (() -> {
441- action .run ();
427+ lastWebViewTask = wakeDisplayAfterFuture (lastWebViewTask .thenRun (action ::run ));
428+ }
429+
430+ <T > CompletableFuture <T > wakeDisplayAfterFuture (CompletableFuture <T > future ) {
431+ return future .handle ((nil1 , nil2 ) -> {
432+ Display display = Display .getDefault ();
433+ if (!display .isDisposed ()) {
434+ try {
435+ display .wake ();
436+ } catch (SWTException e ) {
437+ // ignore then, this can happen due to the async nature between our check for
438+ // disposed and the actual call to wake the display can be disposed
439+ }
440+ }
441+ return null ;
442442 });
443443 }
444-
445- private <T > void waitForFutureToFinish (CompletableFuture <T > future ) {
446- while (!future .isDone ()) {
447- processNextOSMessage ();
448- }
449- }
450-
451444}
452445
453446/**
454- * Processes a single OS message using {@link Display#readAndDispatch()}. This
447+ * Processes single OS messages using {@link Display#readAndDispatch()}. This
455448 * is required for processing the OS events during browser initialization, since
456- * Edge browser initialization happens asynchronously.
449+ * Edge browser initialization happens asynchronously. Messages are processed
450+ * until the given condition is fulfilled or a timeout occurs.
457451 * <p>
458452 * {@link Display#readAndDispatch()} also processes events scheduled for
459453 * asynchronous execution via {@link Display#asyncExec(Runnable)}. This may
@@ -462,13 +456,22 @@ private <T> void waitForFutureToFinish(CompletableFuture<T> future) {
462456 * events for initialization. Thus, this method does not implement an ordinary
463457 * readAndDispatch loop, but waits for an OS event to be processed.
464458 */
465- private static void processNextOSMessage ( ) {
459+ private static void processOSMessagesUntil ( Supplier < Boolean > condition ) {
466460 Display display = Display .getCurrent ();
467461 MSG msg = new MSG ();
468- while (!OS .PeekMessage (msg , 0 , 0 , 0 , OS .PM_NOREMOVE )) {
469- display .sleep ();
462+ AtomicBoolean timeoutOccurred = new AtomicBoolean ();
463+ // The timer call also wakes up the display to avoid being stuck in display.sleep()
464+ display .timerExec ((int ) MAXIMUM_OPERATION_TIME .toMillis (), () -> timeoutOccurred .set (true ));
465+ while (!condition .get () && !timeoutOccurred .get ()) {
466+ if (OS .PeekMessage (msg , 0 , 0 , 0 , OS .PM_NOREMOVE )) {
467+ display .readAndDispatch ();
468+ } else {
469+ display .sleep ();
470+ }
471+ }
472+ if (!condition .get ()) {
473+ SWT .error (SWT .ERROR_UNSPECIFIED , null , " Waiting for Edge operation to terminate timed out" );
470474 }
471- display .readAndDispatch ();
472475}
473476
474477static ICoreWebView2CookieManager getCookieManager () {
0 commit comments