1 /*
2  * Copyright 2016-2020 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 java.util.concurrent.*
11 import javax.swing.*
12 import kotlin.coroutines.*
13 
14 /**
15  * Dispatches execution onto Swing event dispatching thread and provides native [delay] support.
16  */
17 @Suppress("unused")
18 public val Dispatchers.Swing : SwingDispatcher
19     get() = kotlinx.coroutines.swing.Swing
20 
21 /**
22  * Dispatcher for Swing event dispatching thread.
23  *
24  * This class provides type-safety and a point for future extensions.
25  */
26 public sealed class SwingDispatcher : MainCoroutineDispatcher(), Delay {
27     /** @suppress */
dispatchnull28     override fun dispatch(context: CoroutineContext, block: Runnable): Unit = SwingUtilities.invokeLater(block)
29 
30     /** @suppress */
31     override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
32         val timer = schedule(timeMillis, TimeUnit.MILLISECONDS, ActionListener {
33             with(continuation) { resumeUndispatched(Unit) }
34         })
35         continuation.invokeOnCancellation { timer.stop() }
36     }
37 
38     /** @suppress */
invokeOnTimeoutnull39     override fun invokeOnTimeout(timeMillis: Long, block: Runnable, context: CoroutineContext): DisposableHandle {
40         val timer = schedule(timeMillis, TimeUnit.MILLISECONDS, ActionListener {
41             block.run()
42         })
43         return object : DisposableHandle {
44             override fun dispose() {
45                 timer.stop()
46             }
47         }
48     }
49 
schedulenull50     private fun schedule(time: Long, unit: TimeUnit, action: ActionListener): Timer =
51         Timer(unit.toMillis(time).coerceAtMost(Int.MAX_VALUE.toLong()).toInt(), action).apply {
52             isRepeats = false
53             start()
54         }
55 }
56 
57 internal class SwingDispatcherFactory : MainDispatcherFactory {
58     override val loadPriority: Int
59         get() = 0
60 
createDispatchernull61     override fun createDispatcher(allFactories: List<MainDispatcherFactory>): MainCoroutineDispatcher = Swing
62 }
63 
64 private object ImmediateSwingDispatcher : SwingDispatcher() {
65     override val immediate: MainCoroutineDispatcher
66         get() = this
67 
68     override fun isDispatchNeeded(context: CoroutineContext): Boolean = !SwingUtilities.isEventDispatchThread()
69 
70     override fun toString() = toStringInternalImpl() ?: "Swing.immediate"
71 }
72 
73 /**
74  * Dispatches execution onto Swing event dispatching thread and provides native [delay] support.
75  */
76 internal object Swing : SwingDispatcher() {
77     override val immediate: MainCoroutineDispatcher
78         get() = ImmediateSwingDispatcher
79 
toStringnull80     override fun toString() = toStringInternalImpl() ?: "Swing"
81 }
82