From 094dd02789643145ad5dfd41973a25baa3cf3da2 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Fri, 5 Jun 2026 10:13:54 +0200 Subject: [PATCH] IJPL-246446 extract onboarding browser rendering to JCEF module Introduce a browser-page renderer extension for onboarding so the base onboarding module can build UI without depending directly on JCEF. The JCEF-backed renderer lives in its own content module, while onboarding callers gracefully skip browser promo content when that renderer is unavailable. IJ-MR-184958 IJ-MR-184993 IJ-MR-179029 IJ-MR-184126 IJ-MR-181153 IJ-MR-146078 IJ-MR-175479 IJ-MR-186058 IJ-MR-193195 IJ-MR-196957 IJ-MR-199124 IJ-MR-197441 IJ-MR-204135 IJ-MR-204674 GitOrigin-RevId: 7ad4a4c7db26d5f4804845bdb4fa59099b92f19c --- platform/new-ui-onboarding/BUILD.bazel | 2 - .../intellij.platform.ide.newUiOnboarding.iml | 1 - platform/new-ui-onboarding/jcef/BUILD.bazel | 62 +++++++++++++++++++ ...llij.platform.ide.newUiOnboarding.jcef.iml | 35 +++++++++++ .../jcef/module-content.yaml | 3 + ...llij.platform.ide.newUiOnboarding.jcef.xml | 16 +++++ .../JcefNewUiOnboardingBrowserPageRenderer.kt | 35 +++++++++++ .../intellij.platform.ide.newUiOnboarding.xml | 3 + .../NewUiOnboardingBrowserPageRenderer.kt | 19 ++++++ .../newUiOnboarding/NewUiOnboardingUtil.kt | 4 ++ .../newUiOnboarding/steps/RunWidgetStep.kt | 4 +- .../steps/ToolWindowLayoutsStep.kt | 4 +- .../SearchEverywhereStep.kt | 4 +- 13 files changed, 186 insertions(+), 6 deletions(-) create mode 100644 platform/new-ui-onboarding/jcef/BUILD.bazel create mode 100644 platform/new-ui-onboarding/jcef/intellij.platform.ide.newUiOnboarding.jcef.iml create mode 100644 platform/new-ui-onboarding/jcef/module-content.yaml create mode 100644 platform/new-ui-onboarding/jcef/resources/intellij.platform.ide.newUiOnboarding.jcef.xml create mode 100644 platform/new-ui-onboarding/jcef/src/com/intellij/platform/ide/newUiOnboarding/jcef/JcefNewUiOnboardingBrowserPageRenderer.kt create mode 100644 platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/NewUiOnboardingBrowserPageRenderer.kt diff --git a/platform/new-ui-onboarding/BUILD.bazel b/platform/new-ui-onboarding/BUILD.bazel index 05559302a13c..a773bcee40ea 100644 --- a/platform/new-ui-onboarding/BUILD.bazel +++ b/platform/new-ui-onboarding/BUILD.bazel @@ -34,7 +34,6 @@ jvm_library( "//libraries/kotlinx/serialization/json", "//platform/projectModel-api:projectModel", "//platform/statistics", - "//libraries/jcef", "//platform/util:util-ui", ], ) @@ -64,7 +63,6 @@ jvm_library( "//libraries/kotlinx/serialization/json:json_test_lib", "//platform/projectModel-api:projectModel_test_lib", "//platform/statistics:statistics_test_lib", - "//libraries/jcef:jcef_test_lib", "//platform/util:util-ui_test_lib", ], ) diff --git a/platform/new-ui-onboarding/intellij.platform.ide.newUiOnboarding.iml b/platform/new-ui-onboarding/intellij.platform.ide.newUiOnboarding.iml index 9458f23af8a1..960b8066127d 100644 --- a/platform/new-ui-onboarding/intellij.platform.ide.newUiOnboarding.iml +++ b/platform/new-ui-onboarding/intellij.platform.ide.newUiOnboarding.iml @@ -43,7 +43,6 @@ - \ No newline at end of file diff --git a/platform/new-ui-onboarding/jcef/BUILD.bazel b/platform/new-ui-onboarding/jcef/BUILD.bazel new file mode 100644 index 000000000000..5b3e99e28019 --- /dev/null +++ b/platform/new-ui-onboarding/jcef/BUILD.bazel @@ -0,0 +1,62 @@ +load("@rules_jvm//:jvm.bzl", "jvm_library") + +### auto-generated section `build intellij.platform.ide.newUiOnboarding.jcef` start + +jvm_library( + name = "jcef", + srcs = glob( + [ + "src/**/*.kt", + "src/**/*.java", + "src/**/*.form", + ], + allow_empty = True, + ), + module_name = "intellij.platform.ide.newUiOnboarding.jcef", + resource_strip_prefix = "resources", + resources = glob( + ["resources/**/*"], + ), + visibility = ["//visibility:public"], + deps = [ + # do not sort, + "@lib//:jetbrains-annotations", + "//platform/core-api:core", + "//platform/core-impl", + "//platform/platform-api:ide", + "//platform/new-ui-onboarding", + "//platform/ui.jcef", + "//platform/util:util-ui", + ], +) + +jvm_library( + name = "jcef_test_lib", + testonly = True, + srcs = glob( + [], + allow_empty = True, + ), + module_name = "intellij.platform.ide.newUiOnboarding.jcef", + visibility = ["//visibility:public"], + runtime_deps = [ + # do not sort, + ":jcef", + "//platform/core-api:core_test_lib", + "//platform/core-impl:core-impl_test_lib", + "//platform/platform-api:ide_test_lib", + "//platform/new-ui-onboarding:new-ui-onboarding_test_lib", + "//platform/ui.jcef:ui.jcef_test_lib", + "//platform/util:util-ui_test_lib", + ], +) +### auto-generated section `build intellij.platform.ide.newUiOnboarding.jcef` end + +### auto-generated section `iml intellij.platform.ide.newUiOnboarding.jcef` start +exports_files( + [ + "intellij.platform.ide.newUiOnboarding.jcef.iml", + ], + visibility = ["//visibility:public"], +) +### auto-generated section `iml intellij.platform.ide.newUiOnboarding.jcef` end diff --git a/platform/new-ui-onboarding/jcef/intellij.platform.ide.newUiOnboarding.jcef.iml b/platform/new-ui-onboarding/jcef/intellij.platform.ide.newUiOnboarding.jcef.iml new file mode 100644 index 000000000000..78486d9dd6aa --- /dev/null +++ b/platform/new-ui-onboarding/jcef/intellij.platform.ide.newUiOnboarding.jcef.iml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/new-ui-onboarding/jcef/module-content.yaml b/platform/new-ui-onboarding/jcef/module-content.yaml new file mode 100644 index 000000000000..547cda59fa2a --- /dev/null +++ b/platform/new-ui-onboarding/jcef/module-content.yaml @@ -0,0 +1,3 @@ +- name: dist.all/lib/intellij.platform.ide.newUiOnboarding.jcef.jar + modules: + - name: intellij.platform.ide.newUiOnboarding.jcef diff --git a/platform/new-ui-onboarding/jcef/resources/intellij.platform.ide.newUiOnboarding.jcef.xml b/platform/new-ui-onboarding/jcef/resources/intellij.platform.ide.newUiOnboarding.jcef.xml new file mode 100644 index 000000000000..cf600798dda9 --- /dev/null +++ b/platform/new-ui-onboarding/jcef/resources/intellij.platform.ide.newUiOnboarding.jcef.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/platform/new-ui-onboarding/jcef/src/com/intellij/platform/ide/newUiOnboarding/jcef/JcefNewUiOnboardingBrowserPageRenderer.kt b/platform/new-ui-onboarding/jcef/src/com/intellij/platform/ide/newUiOnboarding/jcef/JcefNewUiOnboardingBrowserPageRenderer.kt new file mode 100644 index 000000000000..ab9a44ad0f93 --- /dev/null +++ b/platform/new-ui-onboarding/jcef/src/com/intellij/platform/ide/newUiOnboarding/jcef/JcefNewUiOnboardingBrowserPageRenderer.kt @@ -0,0 +1,35 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.ide.newUiOnboarding.jcef + +import com.intellij.platform.ide.newUiOnboarding.NewUiOnboardingBrowserPageRenderer +import com.intellij.ui.components.panels.Wrapper +import com.intellij.ui.jcef.JBCefApp +import com.intellij.ui.jcef.JBCefBrowser +import com.intellij.util.ui.UIUtil +import org.jetbrains.annotations.ApiStatus +import java.awt.Dimension +import java.awt.Graphics +import javax.swing.JComponent + +@ApiStatus.Internal +class JcefNewUiOnboardingBrowserPageRenderer : NewUiOnboardingBrowserPageRenderer { + override fun createBrowserPageComponent(htmlText: String, size: Dimension): JComponent? { + if (!JBCefApp.isSupported()) { + return null + } + + val browser = JBCefBrowser.createBuilder().setMouseWheelEventEnable(false).build() + browser.loadHTML(htmlText) + return object : Wrapper(browser.component) { + override fun paint(g: Graphics?) { + super.paint(g) + super.paintBorder(g) + } + }.also { + UIUtil.setNotOpaqueRecursively(it) + val adjustedSize = Dimension(size.width + 2, size.height + 2) + it.minimumSize = adjustedSize + it.preferredSize = adjustedSize + } + } +} diff --git a/platform/new-ui-onboarding/resources/intellij.platform.ide.newUiOnboarding.xml b/platform/new-ui-onboarding/resources/intellij.platform.ide.newUiOnboarding.xml index a047e546d2a0..5d4dd530d4da 100644 --- a/platform/new-ui-onboarding/resources/intellij.platform.ide.newUiOnboarding.xml +++ b/platform/new-ui-onboarding/resources/intellij.platform.ide.newUiOnboarding.xml @@ -26,6 +26,9 @@ beanClass="com.intellij.platform.ide.newUiOnboarding.newUi.NewUiOnboardingBean" dynamic="true"> + diff --git a/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/NewUiOnboardingBrowserPageRenderer.kt b/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/NewUiOnboardingBrowserPageRenderer.kt new file mode 100644 index 000000000000..c91e84198a1a --- /dev/null +++ b/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/NewUiOnboardingBrowserPageRenderer.kt @@ -0,0 +1,19 @@ +// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.platform.ide.newUiOnboarding + +import com.intellij.openapi.extensions.ExtensionPointName +import org.jetbrains.annotations.ApiStatus +import java.awt.Dimension +import javax.swing.JComponent + +@ApiStatus.Internal +interface NewUiOnboardingBrowserPageRenderer { + fun createBrowserPageComponent(htmlText: String, size: Dimension): JComponent? + + companion object { + private val EP_NAME = ExtensionPointName("com.intellij.ide.newUiOnboarding.browserPageRenderer") + + fun createComponent(htmlText: String, size: Dimension): JComponent? = + EP_NAME.extensionList.firstNotNullOfOrNull { it.createBrowserPageComponent(htmlText, size) } + } +} diff --git a/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/NewUiOnboardingUtil.kt b/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/NewUiOnboardingUtil.kt index bd3f1e8780e2..d29fc6e9195b 100644 --- a/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/NewUiOnboardingUtil.kt +++ b/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/NewUiOnboardingUtil.kt @@ -59,6 +59,7 @@ import java.awt.Component import java.awt.Dimension import java.awt.Point import java.awt.Rectangle +import javax.swing.JComponent import javax.swing.Icon import javax.swing.SwingUtilities @@ -242,6 +243,9 @@ object NewUiOnboardingUtil { return htmlPage to size } + fun createBrowserPageComponent(htmlText: String, size: Dimension): JComponent? = + NewUiOnboardingBrowserPageRenderer.createComponent(htmlText, size) + suspend fun createSettingsEntryPointPopup(project: Project, disposable: CheckedDisposable): JBPopup? { val settingsButton = UiComponentsSearchUtil.findUiComponent(project) { button: ActionButton -> button.action is SettingsEntryPointAction diff --git a/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/steps/RunWidgetStep.kt b/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/steps/RunWidgetStep.kt index cd7955d69eb1..c9e1b30915eb 100644 --- a/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/steps/RunWidgetStep.kt +++ b/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/steps/RunWidgetStep.kt @@ -57,7 +57,9 @@ open class RunWidgetStep : NewUiOnboardingStep { NewUiOnboardingUtil.createLottieAnimationPage(animationPath, animationClassLoader) } lottiePageData?.let { (html, size) -> - builder.withBrowserPage(html, size, withBorder = true) + NewUiOnboardingUtil.createBrowserPageComponent(html, size)?.let { + builder.withCustomComponentPromo(it, withBorder = true) + } } val point = NewUiOnboardingUtil.convertPointToFrame(project, runPopup.content, JBPoint(-4, 27)) ?: return null diff --git a/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/steps/ToolWindowLayoutsStep.kt b/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/steps/ToolWindowLayoutsStep.kt index b5571f4a93a6..7195473235e5 100644 --- a/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/steps/ToolWindowLayoutsStep.kt +++ b/platform/new-ui-onboarding/src/com/intellij/platform/ide/newUiOnboarding/steps/ToolWindowLayoutsStep.kt @@ -35,7 +35,9 @@ open class ToolWindowLayoutsStep : NewUiOnboardingStep { NewUiOnboardingUtil.createLottieAnimationPage(LOTTIE_JSON_PATH, ToolWindowLayoutsStep::class.java.classLoader) } lottiePageData?.let { (html, size) -> - builder.withBrowserPage(html, size, withBorder = true) + NewUiOnboardingUtil.createBrowserPageComponent(html, size)?.let { + builder.withCustomComponentPromo(it, withBorder = true) + } } return NewUiOnboardingStepData(builder, RelativePoint(ideFrame.rootPane, Point(0, 0)), position = null) // show in the center } diff --git a/platform/new-users-onboarding/src/com/intellij/platform/ide/newUsersOnboarding/SearchEverywhereStep.kt b/platform/new-users-onboarding/src/com/intellij/platform/ide/newUsersOnboarding/SearchEverywhereStep.kt index c6058a1898a5..bc78258d84ef 100644 --- a/platform/new-users-onboarding/src/com/intellij/platform/ide/newUsersOnboarding/SearchEverywhereStep.kt +++ b/platform/new-users-onboarding/src/com/intellij/platform/ide/newUsersOnboarding/SearchEverywhereStep.kt @@ -35,7 +35,9 @@ internal class SearchEverywhereStep : NewUiOnboardingStep { NewUiOnboardingUtil.createLottieAnimationPage(LOTTIE_JSON_PATH, SearchEverywhereStep::class.java.classLoader) } lottiePageData?.let { (html, size) -> - builder.withBrowserPage(html, size, withBorder = true) + NewUiOnboardingUtil.createBrowserPageComponent(html, size)?.let { + builder.withCustomComponentPromo(it, withBorder = true) + } } val point = Point(searchEverywhereButton.width / 2, searchEverywhereButton.height + JBUI.scale(3))