1 /* 2 * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. 3 */ 4 5 package kotlinx.coroutines.swing 6 7 import kotlinx.coroutines.* 8 import kotlinx.coroutines.internal.* 9 import java.awt.event.* 10 import javax.swing.* 11 import kotlin.coroutines.* 12 13 /** 14 * Dispatches execution onto Swing event dispatching thread and provides native [delay] support. 15 */ 16 @Suppress("unused") 17 public val Dispatchers.Swing : SwingDispatcher 18 get() = kotlinx.coroutines.swing.Swing 19 20 /** 21 * Dispatcher for Swing event dispatching thread. 22 * 23 * This class provides type-safety and a point for future extensions. 24 */ 25 public sealed class SwingDispatcher : MainCoroutineDispatcher(), Delay { 26 /** @suppress */ dispatchnull27 override fun dispatch(context: CoroutineContext, block: Runnable): Unit = SwingUtilities.invokeLater(block) 28 29 /** @suppress */ 30 override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) { 31 val timer = schedule(timeMillis) { 32 with(continuation) { resumeUndispatched(Unit) } 33 } 34 continuation.invokeOnCancellation { timer.stop() } 35 } 36 37 /** @suppress */ invokeOnTimeoutnull38 override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle { 39 val timer = schedule(timeMillis) { 40 block.run() 41 } 42 return DisposableHandle { timer.stop() } 43 } 44 schedulenull45 private fun schedule(timeMillis: Long, action: ActionListener): Timer = 46 Timer(timeMillis.coerceAtMost(Int.MAX_VALUE.toLong()).toInt(), action).apply { 47 isRepeats = false 48 start() 49 } 50 } 51 52 internal class SwingDispatcherFactory : MainDispatcherFactory { 53 override val loadPriority: Int 54 get() = 0 55 createDispatchernull56 override fun createDispatcher(allFactories: List<MainDispatcherFactory>): MainCoroutineDispatcher = Swing 57 } 58 59 private object ImmediateSwingDispatcher : SwingDispatcher() { 60 override val immediate: MainCoroutineDispatcher 61 get() = this 62 63 override fun isDispatchNeeded(context: CoroutineContext): Boolean = !SwingUtilities.isEventDispatchThread() 64 65 override fun toString() = toStringInternalImpl() ?: "Swing.immediate" 66 } 67 68 /** 69 * Dispatches execution onto Swing event dispatching thread and provides native [delay] support. 70 */ 71 internal object Swing : SwingDispatcher() { 72 73 /* A workaround so that the dispatcher's initialization crashes with an exception if running in a headless 74 environment. This is needed so that this broken dispatcher is not used as the source of delays. */ 75 init { <lambda>null76 Timer(1) { }.apply { 77 isRepeats = false 78 start() 79 } 80 } 81 82 override val immediate: MainCoroutineDispatcher 83 get() = ImmediateSwingDispatcher 84 toStringnull85 override fun toString() = toStringInternalImpl() ?: "Swing" 86 } 87