From 1d3ffe42080be587d27c1f263b2155a15f58c1bb Mon Sep 17 00:00:00 2001 From: spvessel Date: Thu, 3 Dec 2020 14:02:34 +0300 Subject: [PATCH] Updated cef example according to cfd 0.3.0-build133 --- cef/.gitignore | 1 + cef/build.gradle.kts | 4 +- .../org/jetbrains/compose/desktop/App.kt | 32 ++++-- .../compose/desktop/browser/BrowserState.kt | 54 ++++----- ...BrowserWrapper.kt => CefBrowserWrapper.kt} | 17 ++- .../compose/desktop/browser/CefView.kt | 104 +++++++++--------- 6 files changed, 110 insertions(+), 102 deletions(-) rename cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/{ComposeBrowserWrapper.kt => CefBrowserWrapper.kt} (93%) diff --git a/cef/.gitignore b/cef/.gitignore index 1b6985c009..729c74d4e9 100644 --- a/cef/.gitignore +++ b/cef/.gitignore @@ -3,3 +3,4 @@ # Ignore Gradle build output directory build +third_party/java-cef diff --git a/cef/build.gradle.kts b/cef/build.gradle.kts index 7096673d1b..9ff01f6ae1 100644 --- a/cef/build.gradle.kts +++ b/cef/build.gradle.kts @@ -5,9 +5,9 @@ import kotlin.text.capitalize plugins { // __KOTLIN_COMPOSE_VERSION__ - kotlin("jvm") version "1.4.0" + kotlin("jvm") version "1.4.20" // __LATEST_COMPOSE_RELEASE_VERSION__ - id("org.jetbrains.compose") version "0.1.0-dev97" + id("org.jetbrains.compose") version "0.3.0-build133" id("de.undercouch.download") version "4.1.1" application } diff --git a/cef/src/main/kotlin/org/jetbrains/compose/desktop/App.kt b/cef/src/main/kotlin/org/jetbrains/compose/desktop/App.kt index 873f7a009e..cfbe1a9ecc 100644 --- a/cef/src/main/kotlin/org/jetbrains/compose/desktop/App.kt +++ b/cef/src/main/kotlin/org/jetbrains/compose/desktop/App.kt @@ -1,7 +1,10 @@ package org.jetbrains.compose.desktop import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.MutableState import androidx.compose.desktop.Window +import androidx.compose.desktop.WindowEvents import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer @@ -23,22 +26,31 @@ import org.jetbrains.compose.desktop.browser.BrowserState import org.jetbrains.compose.desktop.browser.CefView fun main() { - Window("CEF-compose", IntSize(800, 800)) { + val browser = BrowserState() + val url = mutableStateOf("https://www.google.com") + + Window( + title = "CEF-compose", + size = IntSize(800, 800), + events = WindowEvents( + onFocusGet = { browser.loadURL(url.value) } + ) + ) { Surface( modifier = Modifier.fillMaxSize(), color = Color.DarkGray ) { Column { - AddressBar() + AddressBar(browser, url) Spacer(Modifier.height(10.dp)) - WebView() + WebView(browser) } } } } @Composable -private fun AddressBar() { +private fun AddressBar(browser: BrowserState, url: MutableState) { Surface( color = Color.Transparent, modifier = Modifier @@ -50,9 +62,9 @@ private fun AddressBar() { backgroundColor = Color.White, activeColor = Color.DarkGray, inactiveColor = Color.DarkGray, - value = BrowserState.url.value, + value = url.value, onValueChange = { - BrowserState.url.value = it + url.value = it }, modifier = Modifier.weight(1f), shape = CircleShape, @@ -62,7 +74,7 @@ private fun AddressBar() { Button( modifier = Modifier.preferredHeight(48.dp), shape = CircleShape, - onClick = { BrowserState.loadURL(BrowserState.url.value) } + onClick = { browser.loadURL(url.value) } ) { Text(text = "Go!") } @@ -71,13 +83,11 @@ private fun AddressBar() { } @Composable -private fun WebView() { +private fun WebView(browser: BrowserState) { Surface( color = Color.Gray, modifier = Modifier.fillMaxSize().padding(10.dp) ) { - if (BrowserState.isReady()) { - CefView() - } + CefView(browser) } } diff --git a/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/BrowserState.kt b/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/BrowserState.kt index 32558fdd1f..e378e40dd1 100644 --- a/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/BrowserState.kt +++ b/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/BrowserState.kt @@ -6,54 +6,34 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.MutableState -import androidx.compose.desktop.AppWindowAmbient import org.jetbrains.skija.Bitmap import org.jetbrains.skiko.HardwareLayer import javax.swing.JFrame import org.cef.CefApp -object BrowserState { - public val url = mutableStateOf("https://www.google.com") - +class BrowserState { + private val url = mutableStateOf("") private val isReady = mutableStateOf(false) - private val frames = mutableStateOf(0) - private lateinit var browser: ComposeBrowserWrapper + private lateinit var browser: CefBrowserWrapper fun isReady(): Boolean { return isReady.value } fun loadURL(url: String) { - if (!isReady.value) { - val app = AppManager.focusedWindow - if (app != null) { - init(app, url) + if (!this::browser.isInitialized) { + val frame = AppManager.focusedWindow + if (frame != null) { + onActive(frame, url) } - } else { - isReady.value = false - browser.loadURL(url) - isReady.value = true - } - } - - fun init(app: AppFrame, url: String) { - val window = app.window - if (!window.isVisible()) { return } - var layer = getHardwareLayer(window) - if (layer == null) { - throw Error("Browser initialization failed!") - } - browser = ComposeBrowserWrapper( - startURL = url, - layer = layer - ) + isReady.value = false + browser.loadURL(url) isReady.value = true } fun getBitmap(): Bitmap { - frames.value++ return browser.getBitmap() } @@ -61,8 +41,22 @@ object BrowserState { browser.onLayout(x, y, width, height) } - fun onActive() { + fun onActive(frame: AppFrame, url: String) { + val window = frame.window + if (!window.isVisible()) { + return + } + var layer = getHardwareLayer(window) + if (layer == null) { + throw Error("Browser initialization failed!") + } + browser = CefBrowserWrapper( + startURL = url, + layer = layer + ) browser.onActive() + + isReady.value = true } fun onDismiss() { diff --git a/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/ComposeBrowserWrapper.kt b/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefBrowserWrapper.kt similarity index 93% rename from cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/ComposeBrowserWrapper.kt rename to cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefBrowserWrapper.kt index 58608b2499..101885b9ac 100644 --- a/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/ComposeBrowserWrapper.kt +++ b/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefBrowserWrapper.kt @@ -26,7 +26,7 @@ import org.cef.handler.CefFocusHandlerAdapter import org.jetbrains.skija.Bitmap import org.jetbrains.skiko.HardwareLayer -open class ComposeBrowserWrapper { +class CefBrowserWrapper { private var offset = IntOffset(0, 0) private var isFocused = false private var cefFocus = true @@ -67,30 +67,35 @@ open class ComposeBrowserWrapper { layer.addMouseListener(object : MouseAdapter() { override fun mousePressed(event: MouseEvent) { - if (isInLayer(event)) + if (isInLayer(event)) { browser.onMouseEvent(event) + } } override fun mouseReleased(event: MouseEvent) { - if (isInLayer(event)) + if (isInLayer(event)) { browser.onMouseEvent(event) + } } }) layer.addMouseMotionListener(object : MouseMotionAdapter() { override fun mouseMoved(event: MouseEvent) { - if (isInLayer(event)) + if (isInLayer(event)) { browser.onMouseEvent(event) + } } override fun mouseDragged(event: MouseEvent) { - if (isInLayer(event)) + if (isInLayer(event)) { browser.onMouseEvent(event) + } } }) layer.addMouseWheelListener(object : MouseWheelListener { override fun mouseWheelMoved(event: MouseWheelEvent) { - if (isInLayer(event)) + if (isInLayer(event)) { browser.onMouseScrollEvent(event) + } } }) diff --git a/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefView.kt b/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefView.kt index 546531a269..bc36af2141 100644 --- a/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefView.kt +++ b/cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefView.kt @@ -1,5 +1,6 @@ package org.jetbrains.compose.desktop.browser +import androidx.compose.desktop.AppWindowAmbient import androidx.compose.runtime.Composable import androidx.compose.runtime.emptyContent import androidx.compose.runtime.mutableStateOf @@ -10,14 +11,16 @@ import androidx.compose.runtime.remember import androidx.compose.foundation.Canvas import androidx.compose.foundation.Image import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.ui.layout +import androidx.compose.ui.layout.layout +import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.globalPosition -import androidx.compose.ui.onPositioned import androidx.compose.material.Surface import androidx.compose.ui.Modifier import org.jetbrains.skija.IRect import org.jetbrains.skija.Bitmap +import org.jetbrains.skija.ImageInfo +import org.jetbrains.skija.ColorAlphaType import androidx.compose.ui.graphics.drawscope.drawIntoCanvas import androidx.compose.ui.graphics.nativeCanvas @@ -39,68 +42,63 @@ private val width = mutableStateOf(0) private val height = mutableStateOf(0) private val x = mutableStateOf(0) private val y = mutableStateOf(0) - -@Composable -fun CefView() { - CefLayout(BrowserState) -} - -@Composable -fun CefLayout(browser: BrowserState) { - - var bitmap by mutableStateOf(browser.getBitmap()) - - browser.onInvalidate( - onInvalidate = { - bitmap = browser.getBitmap() - }) - - CefCanvas(bitmap, browser) - - onActive { - browser.onActive() +private val emptyBitmap: Bitmap + get() { + val bitmap = Bitmap() + bitmap.allocPixels(ImageInfo.makeS32(1, 1, ColorAlphaType.PREMUL)) + return bitmap } - onDispose { - browser.onDismiss() - } -} - -@Composable @OptIn( ExperimentalFocus::class, ExperimentalFoundationApi::class ) -fun CefCanvas(bitmap: Bitmap, browser: BrowserState) { +@Composable +fun CefView(browser: BrowserState) { + val bitmap = remember { mutableStateOf(emptyBitmap) } + val forceRecompose = remember { mutableStateOf(Any()) } val focusRequester = FocusRequester() - Canvas( - modifier = Modifier - .fillMaxSize() - .onResized(browser) - .onPositioned { coordinates -> - x.value = coordinates.globalPosition.x.toInt() - y.value = coordinates.globalPosition.y.toInt() + if (browser.isReady()) { + browser.onInvalidate { + bitmap.value = browser.getBitmap() + forceRecompose.value = Any() } - .focusRequester(focusRequester) - .focusObserver { browser.setFocused(it.isFocused) } - .focus() - .clickable(indication = null) { focusRequester.requestFocus() } - ) { - drawIntoCanvas { canvas -> - canvas.nativeCanvas.drawBitmapRect(bitmap, IRect(0, 0, width.value, height.value).toRect()) + + Canvas( + modifier = Modifier + .fillMaxSize() + .layout { measurable, constraints -> + val placeable = measurable.measure(constraints) + width.value = placeable.width + height.value = placeable.height + browser.onLayout(x.value, y.value, width.value, height.value) + + layout(placeable.width, placeable.height) { + placeable.placeRelative(0, 0) + } + } + .onGloballyPositioned { coordinates -> + x.value = coordinates.globalPosition.x.toInt() + y.value = coordinates.globalPosition.y.toInt() + } + .focusRequester(focusRequester) + .focusObserver { browser.setFocused(it.isFocused) } + .focus() + .clickable(indication = null) { focusRequester.requestFocus() } + ) { + drawIntoCanvas { canvas -> + forceRecompose.value + bitmap.value + canvas.nativeCanvas.drawBitmapRect( + bitmap.value, + IRect(0, 0, width.value, height.value).toRect() + ) + } } } -} - -private fun Modifier.onResized(browser: BrowserState) = Modifier.layout { measurable, constraints -> - val placeable = measurable.measure(constraints) - - width.value = placeable.width - height.value = placeable.height - browser.onLayout(x.value, y.value, width.value, height.value) - layout(placeable.width, placeable.height) { - placeable.placeRelative(0, 0) + onDispose { + browser.onDismiss() } }