diff --git a/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java b/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java index ed25d3b9efce..12213b61d627 100644 --- a/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java +++ b/platform/platform-api/src/com/intellij/ui/jcef/JBCefApp.java @@ -21,18 +21,25 @@ import org.cef.callback.CefSchemeHandlerFactory; import org.cef.callback.CefSchemeRegistrar; import org.cef.handler.CefAppHandlerAdapter; import org.cef.misc.BoolRef; +import org.jdom.IllegalDataException; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import javax.swing.*; import java.awt.*; -import java.lang.reflect.InvocationTargetException; +import java.io.IOException; import java.lang.reflect.Method; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.List; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; import java.util.function.Function; +import java.util.stream.Stream; import static com.intellij.ui.paint.PaintUtil.RoundingMode.ROUND; @@ -57,6 +64,7 @@ public final class JBCefApp { private final @NotNull CefApp myCefApp; private final @NotNull CefSettings myCefSettings; + private final @NotNull CompletableFuture myDebuggingPort = new CompletableFuture<>(); private final @NotNull Disposable myDisposable = new Disposable() { @Override @@ -107,6 +115,20 @@ public final class JBCefApp { CefApp.addAppHandler(new MyCefAppHandler(args, trackGPUCrashes.get())); myCefSettings = settings; myCefApp = CefApp.getInstance(settings); + + if (myCefSettings.remote_debugging_port > 0) { + myDebuggingPort.complete(myCefSettings.remote_debugging_port); + } else { + myCefApp.onInitialization(state -> { + try { + myDebuggingPort.complete(readDebugPortFile(Path.of(myCefSettings.cache_path, "DevToolsActivePort"))); + } + catch (Exception e) { + myDebuggingPort.completeExceptionally(e); + } + }); + } + Disposer.register(ApplicationManager.getApplication(), myDisposable); } @@ -265,12 +287,39 @@ public final class JBCefApp { return myCefSettings.cache_path; } + + /** + * @deprecated use {@link JBCefApp#getRemoteDebuggingPort(Consumer)} instead + */ + @Deprecated @Contract(pure = true) @NotNull public Integer getRemoteDebuggingPort() { return myCefSettings.remote_debugging_port; } + /** + * Schedules passing the debug port number to the consumer once the value is available. + * In case of error, null will be passed to the consumer. The consumer will be called from EDT. + *

+ * Warning: waiting the callback in EDT may result in deadlock. + * + * @param consumer - the port number consumer. + */ + public void getRemoteDebuggingPort(Consumer consumer) { + myDebuggingPort.whenCompleteAsync( + (integer, throwable) -> { + if (throwable != null) { + LOG.error("Failed to get JCEF debugging port: " + throwable.getMessage()); + consumer.accept(null); + } else { + consumer.accept(integer); + } + }, + f -> SwingUtilities.invokeLater(f) + ); + } + public @NotNull JBCefClient createClient() { return createClient(false); } @@ -429,4 +478,19 @@ public final class JBCefApp { protected static boolean isRemoteEnabled() { return IS_REMOTE_ENABLED; } + + static int readDebugPortFile(Path filePath) throws IOException { + try (Stream lines = Files.lines(filePath)) { + String portNumber = lines.findFirst().orElseThrow(() -> { + return new IllegalArgumentException("Failed to read JCEF debugging port number in " + filePath); + }); + + int value = Integer.parseInt(portNumber); + if (value > 0) { + return value; + } + + throw new IllegalDataException("Invalid JCEF JCEF debugging port number value: " + value); + } + } } diff --git a/platform/platform-api/src/com/intellij/ui/jcef/SettingsHelper.java b/platform/platform-api/src/com/intellij/ui/jcef/SettingsHelper.java index a70c0ab32a01..50d98869d3df 100644 --- a/platform/platform-api/src/com/intellij/ui/jcef/SettingsHelper.java +++ b/platform/platform-api/src/com/intellij/ui/jcef/SettingsHelper.java @@ -220,6 +220,10 @@ final class SettingsHelper { args = ArrayUtil.mergeArrays(args, "--disable-gpu-compositing"); } + if (settings.remote_debugging_port == 0 && Registry.intValue("ide.browser.jcef.debug.port") == 0) { + args = ArrayUtil.mergeArrays(args, "--remote-debugging-port=0", "--remote-allow-origins=*"); + } + return args; } diff --git a/platform/util/resources/misc/registry.properties b/platform/util/resources/misc/registry.properties index 4e25486af907..ec1ae49cf3ff 100644 --- a/platform/util/resources/misc/registry.properties +++ b/platform/util/resources/misc/registry.properties @@ -368,7 +368,8 @@ ide.browser.jcef.headless.enabled.description=Enable JCEF browser in the IDE hea ide.browser.jcef.testMode.enabled=false ide.browser.jcef.testMode.enabled.description=Allows for JBCefApp.getInstance() to re-initialize on a subsequent call. ide.browser.jcef.debug.port=-1 -ide.browser.jcef.debug.port.description=Port which can be used for debugging JavaScript in JCEF components +ide.browser.jcef.debug.port.restartRequired=true +ide.browser.jcef.debug.port.description=The port number at which remote DevTools will be available(0 - to select a random) ide.browser.jcef.preinit=false ide.browser.jcef.preinit.restartRequired=true ide.browser.jcef.preinit.description=Force JCEF init at IDE start-up to support co-existence with JavaFX (affects macOS only)