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