Skip to content

Commit

Permalink
Don't depend on kotlinx-coroutines-swing
Browse files Browse the repository at this point in the history
Because it overrides Dispatchers.Main

Fixes JetBrains/compose-multiplatform#1943

RelNote:
Compose don't depend on `kotlinx-coroutines-swing` now. So if you use `Dispatchers.Swing` or `Dispatchers.Main` in your code, add this dependency into `build.gradle.kts`:
```
dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion")
}
```

Change-Id: Iefec704aceb25d03c460a227b3aa0921996f14ed

# Conflicts:
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/ImageComposeSceneTest.kt
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/awt/ComposeWindowTest.kt
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/platform/TestComposeWindowTest.kt
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/TestUtils.kt
#	compose/ui/ui/src/desktopTest/kotlin/androidx/compose/ui/window/window/WindowTest.kt
  • Loading branch information
igordmn authored and Oleksandr Karpovich committed Jun 24, 2022
1 parent 053f658 commit 5395550
Show file tree
Hide file tree
Showing 15 changed files with 32 additions and 40 deletions.
1 change: 0 additions & 1 deletion compose/ui/ui/build.gradle
Expand Up @@ -172,7 +172,6 @@ if(AndroidXComposePlugin.isMultiplatformEnabled(project)) {
dependsOn(skikoMain)
dependencies {
implementation(libs.kotlinStdlibJdk8)
api(libs.kotlinCoroutinesSwing)
}
}

Expand Down
Expand Up @@ -32,7 +32,7 @@ import org.jetbrains.skia.impl.Library
* - sets UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
*
* Should be called before using any class from `java.swing.*`
* (even before SwingUtilities.invokeLater or Dispatchers.Swing)
* (even before SwingUtilities.invokeLater or MainUIDispatcher)
*/
@ExperimentalComposeUiApi
fun configureSwingGlobalsForCompose(
Expand Down
Expand Up @@ -31,9 +31,8 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.window.WindowExceptionHandler
import androidx.compose.ui.window.density
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skia.Canvas
import org.jetbrains.skiko.MainUIDispatcher
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkikoView
import java.awt.Cursor
Expand Down Expand Up @@ -93,7 +92,7 @@ internal class ComposeLayer {
}

internal val scene = ComposeScene(
Dispatchers.Swing + coroutineExceptionHandler,
MainUIDispatcher + coroutineExceptionHandler,
_component,
Density(1f),
_component::needRedraw,
Expand Down
Expand Up @@ -23,7 +23,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.channels.consumeEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.MainUIDispatcher
import java.util.concurrent.atomic.AtomicBoolean

/**
Expand All @@ -34,7 +34,7 @@ import java.util.concurrent.atomic.AtomicBoolean
*
* Composition bootstrapping mechanisms for a particular platform/framework should call
* [ensureStarted] during setup to initialize periodic global snapshot notifications.
* For desktop, these notifications are always sent on [Dispatchers.Swing]. Other platforms
* For desktop, these notifications are always sent on [MainUIDispatcher]. Other platforms
* may establish different policies for these notifications.
*/
internal actual object GlobalSnapshotManager {
Expand All @@ -43,7 +43,8 @@ internal actual object GlobalSnapshotManager {
actual fun ensureStarted() {
if (started.compareAndSet(false, true)) {
val channel = Channel<Unit>(Channel.CONFLATED)
CoroutineScope(Dispatchers.Swing).launch {
Dispatchers.IO
CoroutineScope(MainUIDispatcher).launch {
channel.consumeEach {
// TODO(https://github.com/JetBrains/compose-jb/issues/1854) get rid of synchronized
synchronized(GlobalSnapshotManager) {
Expand Down
Expand Up @@ -41,9 +41,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import org.jetbrains.skiko.MainUIDispatcher
import kotlin.system.exitProcess

/**
Expand Down Expand Up @@ -195,7 +195,7 @@ suspend fun awaitApplication(
if (System.getProperty("compose.application.configure.swing.globals") == "true") {
configureSwingGlobalsForCompose()
}
withContext(Dispatchers.Swing) {
withContext(MainUIDispatcher) {
withContext(YieldFrameClock) {
GlobalSnapshotManager.ensureStarted()

Expand Down
Expand Up @@ -26,11 +26,10 @@ import androidx.compose.ui.node.Ref
import androidx.compose.ui.util.UpdateEffect
import androidx.compose.ui.util.makeDisplayable
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.MainUIDispatcher
import java.awt.Window

/**
Expand Down Expand Up @@ -117,7 +116,7 @@ fun <T : Window> AwtWindow(
// So we will have a wrong active window (window1).

showJob.value?.cancel()
showJob.value = GlobalScope.launch(Dispatchers.Swing) {
showJob.value = GlobalScope.launch(MainUIDispatcher) {
window().isVisible = currentVisible
}
}
Expand Down
Expand Up @@ -39,10 +39,9 @@ import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import kotlin.time.Duration.Companion.seconds
import kotlin.time.ExperimentalTime
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.MainUIDispatcher
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
Expand Down Expand Up @@ -118,7 +117,7 @@ class ImageComposeSceneTest {

@Test(timeout = 5000)
fun `closing ImageComposeScene should not cancel coroutineContext's Job`() {
runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
val scene = ImageComposeScene(100, 100, coroutineContext = coroutineContext)
scene.close()
}
Expand Down
Expand Up @@ -24,9 +24,8 @@ import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.density
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.MainUIDispatcher
import org.junit.Assume
import org.junit.Test
import java.awt.Dimension
Expand All @@ -38,7 +37,7 @@ class ComposePanelTest {
fun `don't override user preferred size`() {
Assume.assumeFalse(GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance)

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
val composePanel = ComposePanel()
composePanel.preferredSize = Dimension(234, 345)
assertThat(composePanel.preferredSize).isEqualTo(Dimension(234, 345))
Expand All @@ -63,7 +62,7 @@ class ComposePanelTest {
fun `pack to Compose content`() {
Assume.assumeFalse(GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance)

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
val composePanel = ComposePanel()
composePanel.setContent {
Box(Modifier.requiredSize(300.dp, 400.dp))
Expand Down Expand Up @@ -93,7 +92,7 @@ class ComposePanelTest {

val layoutPassConstraints = mutableListOf<Constraints>()

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
val composePanel = ComposePanel()
composePanel.setContent {
Box(Modifier.fillMaxSize().layout { _, constraints ->
Expand Down
Expand Up @@ -44,9 +44,8 @@ import java.awt.event.MouseEvent.MOUSE_MOVED
import java.awt.event.MouseEvent.MOUSE_PRESSED
import java.awt.event.MouseEvent.MOUSE_RELEASED
import java.awt.event.WindowEvent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.MainUIDispatcher
import org.junit.Assume
import org.junit.Test

Expand Down Expand Up @@ -142,7 +141,7 @@ class ComposeWindowTest {
fun `don't override user preferred size`() {
Assume.assumeFalse(GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance)

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
val window = ComposeWindow()
try {
window.preferredSize = Dimension(234, 345)
Expand All @@ -160,7 +159,7 @@ class ComposeWindowTest {
fun `pack to Compose content`() {
Assume.assumeFalse(GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance)

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
val window = ComposeWindow()
try {
window.setContent {
Expand All @@ -187,7 +186,7 @@ class ComposeWindowTest {

val layoutPassConstraints = mutableListOf<Constraints>()

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
val window = ComposeWindow()
try {
window.size = Dimension(300, 400)
Expand Down
Expand Up @@ -24,21 +24,20 @@ import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.Density
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.yield
import org.jetbrains.skia.Canvas
import org.jetbrains.skia.Surface
import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.MainUIDispatcher
import kotlin.coroutines.CoroutineContext

internal fun renderingTest(
width: Int,
height: Int,
context: CoroutineContext = Dispatchers.Swing,
context: CoroutineContext = MainUIDispatcher,
block: suspend RenderingTestScope.() -> Unit
) = runBlocking(Dispatchers.Swing) {
) = runBlocking(MainUIDispatcher) {
val scope = RenderingTestScope(width, height, context)
try {
scope.block()
Expand Down
Expand Up @@ -24,16 +24,15 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshots.Snapshot
import java.awt.GraphicsEnvironment
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.takeWhile
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.yield
import org.jetbrains.skiko.MainUIDispatcher
import org.junit.Assume.assumeFalse

@OptIn(ExperimentalCoroutinesApi::class)
Expand All @@ -52,7 +51,7 @@ internal fun runApplicationTest(
) {
assumeFalse(GraphicsEnvironment.getLocalGraphicsEnvironment().isHeadlessInstance)

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
withTimeout(30000) {
val exceptionHandler = TestExceptionHandler()
withExceptionHandler(exceptionHandler) {
Expand Down
Expand Up @@ -394,7 +394,7 @@ class WindowStateTest {
@Test
fun `restore size and position after maximize`() = runApplicationTest {
// Swing/macOs can't re-change isMaximized in a deterministic way:
// fun main() = runBlocking(Dispatchers.Swing) {
// fun main() = runBlocking(MainUIDispatcher) {
// val window = ComposeWindow()
// window.size = Dimension(200, 200)
// window.isVisible = true
Expand Down Expand Up @@ -498,7 +498,7 @@ class WindowStateTest {
@Test
fun `minimize window before show`() = runApplicationTest {
// Linux/macos doesn't support this:
// fun main() = runBlocking(Dispatchers.Swing) {
// fun main() = runBlocking(MainUIDispatcher) {
// val window = ComposeWindow()
// window.size = Dimension(200, 200)
// window.isMinimized = true
Expand Down
Expand Up @@ -50,11 +50,10 @@ import java.awt.Dimension
import java.awt.GraphicsEnvironment
import java.awt.event.WindowAdapter
import java.awt.event.WindowEvent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.MainUIDispatcher
import org.junit.Assume.assumeFalse
import org.junit.Test
import kotlinx.coroutines.cancelAndJoin
Expand Down Expand Up @@ -416,7 +415,7 @@ class WindowTest {

val oldRecomposers = Recomposer.runningRecomposers.value

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
repeat(10) {
val window = ComposeWindow()
window.size = Dimension(200, 200)
Expand Down
Expand Up @@ -24,7 +24,7 @@ package androidx.compose.ui.platform
*
* Composition bootstrapping mechanisms for a particular platform/framework should call
* [ensureStarted] during setup to initialize periodic global snapshot notifications.
* For desktop, these notifications are always sent on [Dispatchers.Swing]. Other platforms
* For desktop, these notifications are always sent on [MainUIDispatcher]. Other platforms
* may establish different policies for these notifications.
*/
internal expect object GlobalSnapshotManager {
Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Expand Up @@ -40,7 +40,7 @@ leakcanary = "2.8.1"
metalava = "1.0.0-alpha06"
mockito = "2.25.0"
protobuf = "3.19.4"
skiko = "0.7.14"
skiko = "0.7.15"
sqldelight = "1.3.0"
wire = "3.6.0"

Expand Down

0 comments on commit 5395550

Please sign in to comment.