Skip to content

Commit 329bae4

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 329bae4

File tree

2 files changed

+96
-18
lines changed

2 files changed

+96
-18
lines changed

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

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,13 @@ 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;
@@ -272,10 +276,14 @@ private static void processNextOSMessage() {
272276
}
273277

274278
static ICoreWebView2CookieManager getCookieManager() {
275-
if (Instances.isEmpty()) {
279+
WebViewEnvironment environmentWrapper = webViewEnvironments.get(Display.getCurrent());
280+
if (environmentWrapper == null) {
281+
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null, " [WebView2: environment not initialized for current display]");
282+
}
283+
if (environmentWrapper.instances().isEmpty()) {
276284
SWT.error(SWT.ERROR_NOT_IMPLEMENTED, null, " [WebView2: cookie access requires a Browser instance]");
277285
}
278-
Edge instance = Instances.get(0);
286+
Edge instance = environmentWrapper.instances.get(0);
279287
if (instance.webView_2 == null) {
280288
SWT.error(SWT.ERROR_NOT_IMPLEMENTED, null, " [WebView2 version 88+ is required to access cookies]");
281289
}
@@ -296,9 +304,10 @@ void checkDeadlock() {
296304
}
297305
}
298306

299-
ICoreWebView2Environment createEnvironment() {
300-
if (Environment != null) return Environment;
307+
WebViewEnvironment createEnvironment() {
301308
Display display = Display.getCurrent();
309+
WebViewEnvironment existingEnvironment = webViewEnvironments.get(display);
310+
if (existingEnvironment != null) return existingEnvironment;
302311

303312
// Gather customization properties
304313
String browserDir = System.getProperty(BROWSER_DIR_PROP);
@@ -336,33 +345,38 @@ ICoreWebView2Environment createEnvironment() {
336345
SWT.error(SWT.ERROR_NOT_IMPLEMENTED, null, " [WebView2 runtime not found]");
337346
}
338347
if (hr != COM.S_OK) error(SWT.ERROR_NO_HANDLES, hr);
339-
Environment = new ICoreWebView2Environment(ppv[0]);
340-
DataDir = dataDir;
348+
ICoreWebView2Environment environment = new ICoreWebView2Environment(ppv[0]);
349+
WebViewEnvironment environmentWrapper = new WebViewEnvironment(environment);
341350

342351
// Save Edge version for reporting
343352
long[] ppVersion = new long[1];
344-
Environment.get_BrowserVersionString(ppVersion);
353+
environment.get_BrowserVersionString(ppVersion);
345354
String version = wstrToString(ppVersion[0], true);
346355
System.setProperty(VERSIONT_PROP, version);
347356

348357
// Destroy the environment on app exit.
349358
display.disposeExec(() -> {
350-
Environment.Release();
351-
Environment = null;
359+
for (Edge instance : environmentWrapper.instances()) {
360+
instance.browserDispose(null);
361+
}
362+
environment.Release();
363+
webViewEnvironments.remove(display);
352364
});
353-
return Environment;
365+
366+
webViewEnvironments.put(display, environmentWrapper);
367+
return environmentWrapper;
354368
}
355369

356370
@Override
357371
public void create(Composite parent, int style) {
358372
checkDeadlock();
359-
ICoreWebView2Environment environment = createEnvironment();
373+
WebViewEnvironment environmentWrapper = createEnvironment();
360374

361375
long[] ppv = new long[1];
362-
int hr = environment.QueryInterface(COM.IID_ICoreWebView2Environment2, ppv);
376+
int hr = environmentWrapper.environment().QueryInterface(COM.IID_ICoreWebView2Environment2, ppv);
363377
if (hr == COM.S_OK) environment2 = new ICoreWebView2Environment2(ppv[0]);
364378

365-
hr = callAndWait(ppv, completion -> environment.CreateCoreWebView2Controller(browser.handle, completion));
379+
hr = callAndWait(ppv, completion -> environmentWrapper.environment().CreateCoreWebView2Controller(browser.handle, completion));
366380
switch (hr) {
367381
case COM.S_OK:
368382
break;
@@ -426,11 +440,11 @@ public void create(Composite parent, int style) {
426440
browser.addListener(SWT.Resize, this::browserResize);
427441
browser.addListener(SWT.Move, this::browserMove);
428442

429-
Instances.add(this);
443+
environmentWrapper.instances().add(this);
430444
}
431445

432446
void browserDispose(Event event) {
433-
Instances.remove(this);
447+
webViewEnvironments.get(Display.getCurrent()).instances().remove(this);
434448

435449
if (webView_2 != null) webView_2.Release();
436450
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: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,70 @@ 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+
isDisposed = browser.isDisposed();
324+
isRunning = false;
325+
}
326+
327+
public void close() {
328+
shouldClose = true;
329+
synchronized (this) {
330+
notifyAll();
331+
}
332+
while (isRunning) {
333+
Thread.yield();
334+
}
335+
}
336+
}
337+
338+
@Test
339+
public void test_Constructor_multipleInstantiationsInDifferentThreads() {
340+
assumeTrue("test case is only relevant on Windows", SwtTestUtil.isWindows);
341+
342+
int numberOfApplication = 5;
343+
List<EdgeBrowserApplication> browserApplications = new ArrayList<>();
344+
for (int i = 0; i < numberOfApplication; i++) {
345+
EdgeBrowserApplication application = new EdgeBrowserApplication();
346+
browserApplications.add(application);
347+
application.start();
348+
}
349+
for (EdgeBrowserApplication application : browserApplications) {
350+
while (!application.isRunning) {
351+
Thread.yield();
352+
}
353+
assertFalse(application.isDisposed);
354+
}
355+
for (EdgeBrowserApplication application : browserApplications) {
356+
application.close();
357+
assertTrue(application.isDisposed);
358+
}
359+
}
360+
297361
@Test
298362
public void test_evalute_Cookies () {
299363
final AtomicBoolean loaded = new AtomicBoolean(false);

0 commit comments

Comments
 (0)