Browse Source

Updated cef example according to cfd 0.3.0-build133

pull/210/head 0.3.0-build134
spvessel 4 years ago
parent
commit
1d3ffe4208
  1. 1
      cef/.gitignore
  2. 4
      cef/build.gradle.kts
  3. 32
      cef/src/main/kotlin/org/jetbrains/compose/desktop/App.kt
  4. 48
      cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/BrowserState.kt
  5. 17
      cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefBrowserWrapper.kt
  6. 82
      cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefView.kt

1
cef/.gitignore vendored

@ -3,3 +3,4 @@
# Ignore Gradle build output directory # Ignore Gradle build output directory
build build
third_party/java-cef

4
cef/build.gradle.kts

@ -5,9 +5,9 @@ import kotlin.text.capitalize
plugins { plugins {
// __KOTLIN_COMPOSE_VERSION__ // __KOTLIN_COMPOSE_VERSION__
kotlin("jvm") version "1.4.0" kotlin("jvm") version "1.4.20"
// __LATEST_COMPOSE_RELEASE_VERSION__ // __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" id("de.undercouch.download") version "4.1.1"
application application
} }

32
cef/src/main/kotlin/org/jetbrains/compose/desktop/App.kt

@ -1,7 +1,10 @@
package org.jetbrains.compose.desktop package org.jetbrains.compose.desktop
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.MutableState
import androidx.compose.desktop.Window import androidx.compose.desktop.Window
import androidx.compose.desktop.WindowEvents
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -23,22 +26,31 @@ import org.jetbrains.compose.desktop.browser.BrowserState
import org.jetbrains.compose.desktop.browser.CefView import org.jetbrains.compose.desktop.browser.CefView
fun main() { 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( Surface(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
color = Color.DarkGray color = Color.DarkGray
) { ) {
Column { Column {
AddressBar() AddressBar(browser, url)
Spacer(Modifier.height(10.dp)) Spacer(Modifier.height(10.dp))
WebView() WebView(browser)
} }
} }
} }
} }
@Composable @Composable
private fun AddressBar() { private fun AddressBar(browser: BrowserState, url: MutableState<String>) {
Surface( Surface(
color = Color.Transparent, color = Color.Transparent,
modifier = Modifier modifier = Modifier
@ -50,9 +62,9 @@ private fun AddressBar() {
backgroundColor = Color.White, backgroundColor = Color.White,
activeColor = Color.DarkGray, activeColor = Color.DarkGray,
inactiveColor = Color.DarkGray, inactiveColor = Color.DarkGray,
value = BrowserState.url.value, value = url.value,
onValueChange = { onValueChange = {
BrowserState.url.value = it url.value = it
}, },
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
shape = CircleShape, shape = CircleShape,
@ -62,7 +74,7 @@ private fun AddressBar() {
Button( Button(
modifier = Modifier.preferredHeight(48.dp), modifier = Modifier.preferredHeight(48.dp),
shape = CircleShape, shape = CircleShape,
onClick = { BrowserState.loadURL(BrowserState.url.value) } onClick = { browser.loadURL(url.value) }
) { ) {
Text(text = "Go!") Text(text = "Go!")
} }
@ -71,13 +83,11 @@ private fun AddressBar() {
} }
@Composable @Composable
private fun WebView() { private fun WebView(browser: BrowserState) {
Surface( Surface(
color = Color.Gray, color = Color.Gray,
modifier = Modifier.fillMaxSize().padding(10.dp) modifier = Modifier.fillMaxSize().padding(10.dp)
) { ) {
if (BrowserState.isReady()) { CefView(browser)
CefView()
}
} }
} }

48
cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/BrowserState.kt

@ -6,38 +6,43 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.desktop.AppWindowAmbient
import org.jetbrains.skija.Bitmap import org.jetbrains.skija.Bitmap
import org.jetbrains.skiko.HardwareLayer import org.jetbrains.skiko.HardwareLayer
import javax.swing.JFrame import javax.swing.JFrame
import org.cef.CefApp import org.cef.CefApp
object BrowserState { class BrowserState {
public val url = mutableStateOf("https://www.google.com") private val url = mutableStateOf("")
private val isReady = mutableStateOf(false) private val isReady = mutableStateOf(false)
private val frames = mutableStateOf(0) private lateinit var browser: CefBrowserWrapper
private lateinit var browser: ComposeBrowserWrapper
fun isReady(): Boolean { fun isReady(): Boolean {
return isReady.value return isReady.value
} }
fun loadURL(url: String) { fun loadURL(url: String) {
if (!isReady.value) { if (!this::browser.isInitialized) {
val app = AppManager.focusedWindow val frame = AppManager.focusedWindow
if (app != null) { if (frame != null) {
init(app, url) onActive(frame, url)
}
return
} }
} else {
isReady.value = false isReady.value = false
browser.loadURL(url) browser.loadURL(url)
isReady.value = true isReady.value = true
} }
fun getBitmap(): Bitmap {
return browser.getBitmap()
}
fun onLayout(x: Int, y: Int, width: Int, height: Int) {
browser.onLayout(x, y, width, height)
} }
fun init(app: AppFrame, url: String) { fun onActive(frame: AppFrame, url: String) {
val window = app.window val window = frame.window
if (!window.isVisible()) { if (!window.isVisible()) {
return return
} }
@ -45,24 +50,13 @@ object BrowserState {
if (layer == null) { if (layer == null) {
throw Error("Browser initialization failed!") throw Error("Browser initialization failed!")
} }
browser = ComposeBrowserWrapper( browser = CefBrowserWrapper(
startURL = url, startURL = url,
layer = layer layer = layer
) )
isReady.value = true
}
fun getBitmap(): Bitmap {
frames.value++
return browser.getBitmap()
}
fun onLayout(x: Int, y: Int, width: Int, height: Int) {
browser.onLayout(x, y, width, height)
}
fun onActive() {
browser.onActive() browser.onActive()
isReady.value = true
} }
fun onDismiss() { fun onDismiss() {

17
cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/ComposeBrowserWrapper.kt → 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.skija.Bitmap
import org.jetbrains.skiko.HardwareLayer import org.jetbrains.skiko.HardwareLayer
open class ComposeBrowserWrapper { class CefBrowserWrapper {
private var offset = IntOffset(0, 0) private var offset = IntOffset(0, 0)
private var isFocused = false private var isFocused = false
private var cefFocus = true private var cefFocus = true
@ -67,31 +67,36 @@ open class ComposeBrowserWrapper {
layer.addMouseListener(object : MouseAdapter() { layer.addMouseListener(object : MouseAdapter() {
override fun mousePressed(event: MouseEvent) { override fun mousePressed(event: MouseEvent) {
if (isInLayer(event)) if (isInLayer(event)) {
browser.onMouseEvent(event) browser.onMouseEvent(event)
} }
}
override fun mouseReleased(event: MouseEvent) { override fun mouseReleased(event: MouseEvent) {
if (isInLayer(event)) if (isInLayer(event)) {
browser.onMouseEvent(event) browser.onMouseEvent(event)
} }
}
}) })
layer.addMouseMotionListener(object : MouseMotionAdapter() { layer.addMouseMotionListener(object : MouseMotionAdapter() {
override fun mouseMoved(event: MouseEvent) { override fun mouseMoved(event: MouseEvent) {
if (isInLayer(event)) if (isInLayer(event)) {
browser.onMouseEvent(event) browser.onMouseEvent(event)
} }
}
override fun mouseDragged(event: MouseEvent) { override fun mouseDragged(event: MouseEvent) {
if (isInLayer(event)) if (isInLayer(event)) {
browser.onMouseEvent(event) browser.onMouseEvent(event)
} }
}
}) })
layer.addMouseWheelListener(object : MouseWheelListener { layer.addMouseWheelListener(object : MouseWheelListener {
override fun mouseWheelMoved(event: MouseWheelEvent) { override fun mouseWheelMoved(event: MouseWheelEvent) {
if (isInLayer(event)) if (isInLayer(event)) {
browser.onMouseScrollEvent(event) browser.onMouseScrollEvent(event)
} }
}
}) })
layer.addKeyListener(object : KeyAdapter() { layer.addKeyListener(object : KeyAdapter() {

82
cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefView.kt

@ -1,5 +1,6 @@
package org.jetbrains.compose.desktop.browser package org.jetbrains.compose.desktop.browser
import androidx.compose.desktop.AppWindowAmbient
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.emptyContent import androidx.compose.runtime.emptyContent
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -10,14 +11,16 @@ import androidx.compose.runtime.remember
import androidx.compose.foundation.Canvas import androidx.compose.foundation.Canvas
import androidx.compose.foundation.Image import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.fillMaxSize 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.layout.globalPosition
import androidx.compose.ui.onPositioned
import androidx.compose.material.Surface import androidx.compose.material.Surface
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import org.jetbrains.skija.IRect import org.jetbrains.skija.IRect
import org.jetbrains.skija.Bitmap 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.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas import androidx.compose.ui.graphics.nativeCanvas
@ -39,46 +42,43 @@ private val width = mutableStateOf(0)
private val height = mutableStateOf(0) private val height = mutableStateOf(0)
private val x = mutableStateOf(0) private val x = mutableStateOf(0)
private val y = mutableStateOf(0) private val y = mutableStateOf(0)
private val emptyBitmap: Bitmap
@Composable get() {
fun CefView() { val bitmap = Bitmap()
CefLayout(BrowserState) bitmap.allocPixels(ImageInfo.makeS32(1, 1, ColorAlphaType.PREMUL))
} return bitmap
@Composable
fun CefLayout(browser: BrowserState) {
var bitmap by mutableStateOf(browser.getBitmap())
browser.onInvalidate(
onInvalidate = {
bitmap = browser.getBitmap()
})
CefCanvas(bitmap, browser)
onActive {
browser.onActive()
}
onDispose {
browser.onDismiss()
} }
}
@Composable
@OptIn( @OptIn(
ExperimentalFocus::class, ExperimentalFocus::class,
ExperimentalFoundationApi::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() val focusRequester = FocusRequester()
if (browser.isReady()) {
browser.onInvalidate {
bitmap.value = browser.getBitmap()
forceRecompose.value = Any()
}
Canvas( Canvas(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.onResized(browser) .layout { measurable, constraints ->
.onPositioned { coordinates -> 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() x.value = coordinates.globalPosition.x.toInt()
y.value = coordinates.globalPosition.y.toInt() y.value = coordinates.globalPosition.y.toInt()
} }
@ -88,19 +88,17 @@ fun CefCanvas(bitmap: Bitmap, browser: BrowserState) {
.clickable(indication = null) { focusRequester.requestFocus() } .clickable(indication = null) { focusRequester.requestFocus() }
) { ) {
drawIntoCanvas { canvas -> drawIntoCanvas { canvas ->
canvas.nativeCanvas.drawBitmapRect(bitmap, IRect(0, 0, width.value, height.value).toRect()) 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) { onDispose {
placeable.placeRelative(0, 0) browser.onDismiss()
} }
} }

Loading…
Cancel
Save