• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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