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. 54
      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. 104
      cef/src/main/kotlin/org/jetbrains/compose/desktop/browser/CefView.kt

1
cef/.gitignore vendored

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

4
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
}

32
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<String>) {
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)
}
}

54
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() {

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.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)
}
}
})

104
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()
}
onDispose {
browser.onDismiss()
private val emptyBitmap: Bitmap
get() {
val bitmap = Bitmap()
bitmap.allocPixels(ImageInfo.makeS32(1, 1, ColorAlphaType.PREMUL))
return bitmap
}
}
@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()
}
}

Loading…
Cancel
Save