Skip to content

Commit

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

Fixes JetBrains/compose-multiplatform#1943 on skiko side
  • Loading branch information
igordmn committed Mar 9, 2022
1 parent 95ef46b commit 617eae5
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 19 deletions.
6 changes: 0 additions & 6 deletions skiko/build.gradle.kts
Expand Up @@ -273,9 +273,6 @@ kotlin {

val awtMain by getting {
dependsOn(jvmMain)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion")
}
}

if (supportAndroid) {
Expand All @@ -298,9 +295,6 @@ kotlin {

val awtTest by getting {
dependsOn(jvmTest)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:$coroutinesVersion")
}
}

if (supportAndroid) {
Expand Down
Expand Up @@ -2,7 +2,6 @@ package org.jetbrains.skiko

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.swing.Swing
import java.awt.*
import java.awt.event.FocusEvent
import java.awt.event.InputMethodEvent
Expand Down Expand Up @@ -110,7 +109,7 @@ internal open class HardwareLayer(
// and its accessibility context. This timeout is used to deal with concurrency
// TODO Find more reliable procedure
resetFocusAccessibleJob?.cancel()
resetFocusAccessibleJob = GlobalScope.launch(Dispatchers.Swing) {
resetFocusAccessibleJob = GlobalScope.launch(MainUIDispatcher) {
delay(100)
_focusedAccessible = null
}
Expand Down
@@ -0,0 +1,57 @@
package org.jetbrains.skiko

import kotlinx.coroutines.*
import java.awt.event.ActionListener
import java.lang.Runnable
import java.util.concurrent.TimeUnit
import javax.swing.SwingUtilities
import javax.swing.Timer
import kotlin.coroutines.CoroutineContext

/**
* Dispatcher for UI thread, which is used in the current implementation of native UI integration.
* Currently, it uses Swing event dispatching thread.
*/
val MainUIDispatcher: CoroutineDispatcher
get() = SwingDispatcher

/**
* Dispatcher for Swing event dispatching thread.
*
* Copy of Dispatchers.Swing from kotlinx-coroutines-swing.
*
* We don't depend on kotlinx-coroutines-swing, because it will override Dispatchers.Main, and
* application can require a different Dispatchers.Main.
*
* Note, that we use internal API `Delay` and experimental `resumeUndispatched`.
* That means it can be changed in the future. When it happens, we need
* to release a new version of Skiko.
*/
@OptIn(InternalCoroutinesApi::class, ExperimentalCoroutinesApi::class)
private object SwingDispatcher : CoroutineDispatcher(), Delay {
override fun dispatch(context: CoroutineContext, block: Runnable): Unit = SwingUtilities.invokeLater(block)

override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
val timer = schedule(timeMillis, TimeUnit.MILLISECONDS) {
with(continuation) { resumeUndispatched(Unit) }
}
continuation.invokeOnCancellation { timer.stop() }
}

override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle {
val timer = schedule(timeMillis, TimeUnit.MILLISECONDS) {
block.run()
}
return object : DisposableHandle {
override fun dispose() {
timer.stop()
}
}
}

private fun schedule(time: Long, unit: TimeUnit, action: ActionListener): Timer =
Timer(unit.toMillis(time).coerceAtMost(Int.MAX_VALUE.toLong()).toInt(), action).apply {
isRepeats = false
start()
}
}
Expand Up @@ -5,6 +5,7 @@ import kotlinx.coroutines.*
import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.FrameLimiter
import org.jetbrains.skiko.RenderException
import org.jetbrains.skiko.MainUIDispatcher
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties
import org.jetbrains.skiko.context.DirectSoftwareContextHandler
Expand Down
Expand Up @@ -3,6 +3,7 @@ package org.jetbrains.skiko.redrawer
import org.jetbrains.skia.BackendRenderTarget
import org.jetbrains.skia.DirectContext
import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.MainUIDispatcher
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties
import org.jetbrains.skiko.context.AngleContextHandler
Expand Down

This file was deleted.

Expand Up @@ -3,6 +3,7 @@ package org.jetbrains.skiko.redrawer
import kotlinx.coroutines.*
import org.jetbrains.skiko.FrameDispatcher
import org.jetbrains.skiko.FrameLimiter
import org.jetbrains.skiko.MainUIDispatcher
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkiaLayerProperties
import org.jetbrains.skiko.context.SoftwareContextHandler
Expand Down
4 changes: 1 addition & 3 deletions skiko/src/jvmTest/kotlin/org/jetbrains/skiko/util/UiTest.kt
@@ -1,9 +1,7 @@
package org.jetbrains.skiko.util

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.swing.Swing
import org.jetbrains.skiko.*
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeTrue
Expand All @@ -16,7 +14,7 @@ internal fun uiTest(block: suspend UiTestScope.() -> Unit) {

val renderApi = System.getProperty("skiko.test.ui.renderApi", "all")

runBlocking(Dispatchers.Swing) {
runBlocking(MainUIDispatcher) {
if (renderApi == "all") {
SkikoProperties.fallbackRenderApiQueue(SkikoProperties.renderApi).forEach {
println("Testing $it renderApi")
Expand Down

0 comments on commit 617eae5

Please sign in to comment.