Skip to content

Commit 3241d04

Browse files
committed
Support Edge instances in different displays #1013
The current implementation of the Edge browser creates a WebView2Environment on first creation of an WebView2 / Edge browser instance. On every further creation of a WebView2 instance, this environment is used. In case the WebView2 instance is created for a different display, i.e., within a different thread, the instantiation fails as the WebView2Environment has been created in a different thread. To support the creation of WebView2 instances in different displays, this change replaces the static WebView2Environment with one environment for every display. The WebView2 instances are created for the environment belonging to the display for which the current instantiation is requested. An according regression test is added. Contributes to #1013
1 parent 44432b2 commit 3241d04

File tree

2 files changed

+95
-18
lines changed

2 files changed

+95
-18
lines changed

bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/Edge.java

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,22 @@ class Edge extends WebBrowser {
4444
static final String LANGUAGE_PROP = "org.eclipse.swt.browser.EdgeLanguage";
4545
static final String VERSIONT_PROP = "org.eclipse.swt.browser.EdgeVersion";
4646

47-
static String DataDir;
48-
static ICoreWebView2Environment Environment;
49-
static ArrayList<Edge> Instances = new ArrayList<>();
47+
private record WebViewEnvironment(ICoreWebView2Environment environment, ArrayList<Edge> instances) {
48+
public WebViewEnvironment(ICoreWebView2Environment environment) {
49+
this (environment, new ArrayList<>());
50+
}
51+
}
52+
53+
private static Map<Display, WebViewEnvironment> webViewEnvironments = new HashMap<>();
5054

5155
ICoreWebView2 webView;
5256
ICoreWebView2_2 webView_2;
5357
ICoreWebView2Controller controller;
5458
ICoreWebView2Settings settings;
5559
ICoreWebView2Environment2 environment2;
5660

61+
WebViewEnvironment containingEnvironment;
62+
5763
static boolean inCallback;
5864
boolean inNewWindow;
5965
HashMap<Long, LocationEvent> navigations = new HashMap<>();
@@ -272,10 +278,14 @@ private static void processNextOSMessage() {
272278
}
273279

274280
static ICoreWebView2CookieManager getCookieManager() {
275-
if (Instances.isEmpty()) {
281+
WebViewEnvironment environmentWrapper = webViewEnvironments.get(Display.getCurrent());
282+
if (environmentWrapper == null) {
283+
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, " [WebView2: environment not initialized for current display]");
284+
}
285+
if (environmentWrapper.instances().isEmpty()) {
276286
SWT.error(SWT.ERROR_NOT_IMPLEMENTED, null, " [WebView2: cookie access requires a Browser instance]");
277287
}
278-
Edge instance = Instances.get(0);
288+
Edge instance = environmentWrapper.instances().get(0);
279289
if (instance.webView_2 == null) {
280290
SWT.error(SWT.ERROR_NOT_IMPLEMENTED, null, " [WebView2 version 88+ is required to access cookies]");
281291
}
@@ -296,9 +306,10 @@ void checkDeadlock() {
296306
}
297307
}
298308

299-
ICoreWebView2Environment createEnvironment() {
300-
if (Environment != null) return Environment;
309+
WebViewEnvironment createEnvironment() {
301310
Display display = Display.getCurrent();
311+
WebViewEnvironment existingEnvironment = webViewEnvironments.get(display);
312+
if (existingEnvironment != null) return existingEnvironment;
302313

303314
// Gather customization properties
304315
String browserDir = System.getProperty(BROWSER_DIR_PROP);
@@ -336,33 +347,38 @@ ICoreWebView2Environment createEnvironment() {
336347
SWT.error(SWT.ERROR_NOT_IMPLEMENTED, null, " [WebView2 runtime not found]");
337348
}
338349
if (hr != COM.S_OK) error(SWT.ERROR_NO_HANDLES, hr);
339-
Environment = new ICoreWebView2Environment(ppv[0]);
340-
DataDir = dataDir;
350+
ICoreWebView2Environment environment = new ICoreWebView2Environment(ppv[0]);
351+
WebViewEnvironment environmentWrapper = new WebViewEnvironment(environment);
341352

342353
// Save Edge version for reporting
343354
long[] ppVersion = new long[1];
344-
Environment.get_BrowserVersionString(ppVersion);
355+
environment.get_BrowserVersionString(ppVersion);
345356
String version = wstrToString(ppVersion[0], true);
346357
System.setProperty(VERSIONT_PROP, version);
347358

348359
// Destroy the environment on app exit.
349360
display.disposeExec(() -> {
350-
Environment.Release();
351-
Environment = null;
361+
for (Edge instance : environmentWrapper.instances()) {
362+
instance.browserDispose(null);
363+
}
364+
environment.Release();
365+
webViewEnvironments.remove(display);
352366
});
353-
return Environment;
367+
368+
webViewEnvironments.put(display, environmentWrapper);
369+
return environmentWrapper;
354370
}
355371

356372
@Override
357373
public void create(Composite parent, int style) {
358374
checkDeadlock();
359-
ICoreWebView2Environment environment = createEnvironment();
375+
containingEnvironment = createEnvironment();
360376

361377
long[] ppv = new long[1];
362-
int hr = environment.QueryInterface(COM.IID_ICoreWebView2Environment2, ppv);
378+
int hr = containingEnvironment.environment().QueryInterface(COM.IID_ICoreWebView2Environment2, ppv);
363379
if (hr == COM.S_OK) environment2 = new ICoreWebView2Environment2(ppv[0]);
364380

365-
hr = callAndWait(ppv, completion -> environment.CreateCoreWebView2Controller(browser.handle, completion));
381+
hr = callAndWait(ppv, completion -> containingEnvironment.environment().CreateCoreWebView2Controller(browser.handle, completion));
366382
switch (hr) {
367383
case COM.S_OK:
368384
break;
@@ -426,11 +442,11 @@ public void create(Composite parent, int style) {
426442
browser.addListener(SWT.Resize, this::browserResize);
427443
browser.addListener(SWT.Move, this::browserMove);
428444

429-
Instances.add(this);
445+
containingEnvironment.instances().add(this);
430446
}
431447

432448
void browserDispose(Event event) {
433-
Instances.remove(this);
449+
containingEnvironment.instances.remove(this);
434450

435451
if (webView_2 != null) webView_2.Release();
436452
if (environment2 != null) environment2.Release();

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_browser_Browser.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,67 @@ public void test_Constructor_multipleInstantiationsInDifferentShells() {
294294
}
295295
}
296296

297+
private class EdgeBrowserApplication extends Thread {
298+
private volatile boolean shouldClose;
299+
private volatile boolean isRunning;
300+
private volatile boolean isDisposed;
301+
302+
@Override
303+
public void run() {
304+
Display threadDisplay = new Display();
305+
Shell browserShell = new Shell(threadDisplay);
306+
Browser browser = createBrowser(browserShell, SWT.EDGE);
307+
browserShell.setVisible(true);
308+
isDisposed = browser.isDisposed();
309+
isRunning = true;
310+
311+
while (!shouldClose) {
312+
synchronized (this) {
313+
try {
314+
wait();
315+
} catch (InterruptedException e) {
316+
shouldClose = true;
317+
}
318+
}
319+
}
320+
321+
browser.dispose();
322+
browserShell.dispose();
323+
threadDisplay.dispose();
324+
isDisposed = browser.isDisposed();
325+
isRunning = false;
326+
}
327+
328+
public void close() {
329+
shouldClose = true;
330+
synchronized (this) {
331+
notifyAll();
332+
}
333+
waitForPassCondition(() -> !isRunning);
334+
}
335+
}
336+
337+
@Test
338+
public void test_Constructor_multipleInstantiationsInDifferentThreads() {
339+
assumeTrue("test case is only relevant on Windows", SwtTestUtil.isWindows);
340+
341+
int numberOfApplication = 5;
342+
List<EdgeBrowserApplication> browserApplications = new ArrayList<>();
343+
for (int i = 0; i < numberOfApplication; i++) {
344+
EdgeBrowserApplication application = new EdgeBrowserApplication();
345+
browserApplications.add(application);
346+
application.start();
347+
}
348+
for (EdgeBrowserApplication application : browserApplications) {
349+
waitForPassCondition(() -> application.isRunning);
350+
assertFalse(application.isDisposed);
351+
}
352+
for (EdgeBrowserApplication application : browserApplications) {
353+
application.close();
354+
assertTrue(application.isDisposed);
355+
}
356+
}
357+
297358
@Test
298359
public void test_evalute_Cookies () {
299360
final AtomicBoolean loaded = new AtomicBoolean(false);

0 commit comments

Comments
 (0)