chore: swing CoroutineScope

This commit is contained in:
hstyi
2025-04-01 15:36:17 +08:00
committed by hstyi
parent 744e64b359
commit d90fb9aa35
12 changed files with 38 additions and 36 deletions

View File

@@ -3,7 +3,6 @@ package app.termora
import com.formdev.flatlaf.util.SystemInfo import com.formdev.flatlaf.util.SystemInfo
import com.jthemedetecor.util.OsInfo import com.jthemedetecor.util.OsInfo
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@@ -123,19 +122,18 @@ object Application {
return "Termora" return "Termora"
} }
@Suppress("OPT_IN_USAGE")
fun browse(uri: URI, async: Boolean = true) { fun browse(uri: URI, async: Boolean = true) {
// https://github.com/TermoraDev/termora/issues/178 // https://github.com/TermoraDev/termora/issues/178
if (SystemInfo.isWindows && uri.scheme == "file") { if (SystemInfo.isWindows && uri.scheme == "file") {
if (async) { if (async) {
GlobalScope.launch(Dispatchers.IO) { tryBrowse(uri) } swingCoroutineScope.launch(Dispatchers.IO) { tryBrowse(uri) }
} else { } else {
tryBrowse(uri) tryBrowse(uri)
} }
} else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { } else if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
Desktop.getDesktop().browse(uri) Desktop.getDesktop().browse(uri)
} else if (async) { } else if (async) {
GlobalScope.launch(Dispatchers.IO) { tryBrowse(uri) } swingCoroutineScope.launch(Dispatchers.IO) { tryBrowse(uri) }
} else { } else {
tryBrowse(uri) tryBrowse(uri)
} }

View File

@@ -12,9 +12,7 @@ import com.jthemedetecor.OsThemeDetector
import com.mixpanel.mixpanelapi.ClientDelivery import com.mixpanel.mixpanelapi.ClientDelivery
import com.mixpanel.mixpanelapi.MessageBuilder import com.mixpanel.mixpanelapi.MessageBuilder
import com.mixpanel.mixpanelapi.MixpanelAPI import com.mixpanel.mixpanelapi.MixpanelAPI
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.apache.commons.io.FileUtils import org.apache.commons.io.FileUtils
import org.apache.commons.lang3.LocaleUtils import org.apache.commons.lang3.LocaleUtils
@@ -51,8 +49,7 @@ class ApplicationRunner {
val enableAnalytics = measureTimeMillis { enableAnalytics() } val enableAnalytics = measureTimeMillis { enableAnalytics() }
// init ActionManager、KeymapManager // init ActionManager、KeymapManager
@Suppress("OPT_IN_USAGE") swingCoroutineScope.launch(Dispatchers.IO) {
GlobalScope.launch(Dispatchers.IO) {
ActionManager.getInstance() ActionManager.getInstance()
KeymapManager.getInstance() KeymapManager.getInstance()
} }
@@ -89,9 +86,8 @@ class ApplicationRunner {
} }
} }
@Suppress("OPT_IN_USAGE")
private fun clearTemporary() { private fun clearTemporary() {
GlobalScope.launch(Dispatchers.IO) { swingCoroutineScope.launch(Dispatchers.IO) {
// 启动时清除 // 启动时清除
FileUtils.cleanDirectory(Application.getTemporaryDir()) FileUtils.cleanDirectory(Application.getTemporaryDir())
} }
@@ -273,13 +269,12 @@ class ApplicationRunner {
/** /**
* 统计 https://mixpanel.com * 统计 https://mixpanel.com
*/ */
@OptIn(DelicateCoroutinesApi::class)
private fun enableAnalytics() { private fun enableAnalytics() {
if (Application.isUnknownVersion()) { if (Application.isUnknownVersion()) {
return return
} }
GlobalScope.launch(Dispatchers.IO) { swingCoroutineScope.launch(Dispatchers.IO) {
try { try {
val properties = JSONObject() val properties = JSONObject()
properties.put("os", SystemUtils.OS_NAME) properties.put("os", SystemUtils.OS_NAME)

View File

@@ -11,7 +11,6 @@ import app.termora.terminal.CursorStyle
import jetbrains.exodus.bindings.StringBinding import jetbrains.exodus.bindings.StringBinding
import jetbrains.exodus.env.* import jetbrains.exodus.env.*
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.apache.commons.io.IOUtils import org.apache.commons.io.IOUtils
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
@@ -348,8 +347,7 @@ class Database private constructor(private val env: Environment) : Disposable {
private val properties = Collections.synchronizedMap(mutableMapOf<String, String>()) private val properties = Collections.synchronizedMap(mutableMapOf<String, String>())
init { init {
@Suppress("OPT_IN_USAGE") swingCoroutineScope.launch(Dispatchers.IO) { properties.putAll(getProperties()) }
GlobalScope.launch(Dispatchers.IO) { properties.putAll(getProperties()) }
} }
protected open fun getString(key: String): String? { protected open fun getString(key: String): String? {

View File

@@ -222,7 +222,7 @@ abstract class DialogWrapper(owner: Window?) : JDialog(owner) {
return return
} }
doCancelAction() SwingUtilities.invokeLater { doCancelAction() }
} }
}) })

View File

@@ -2,8 +2,10 @@ package app.termora
import app.termora.actions.AnAction import app.termora.actions.AnAction
import app.termora.actions.AnActionEvent import app.termora.actions.AnActionEvent
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext
import org.apache.commons.lang3.exception.ExceptionUtils import org.apache.commons.lang3.exception.ExceptionUtils
import org.apache.sshd.client.SshClient import org.apache.sshd.client.SshClient
import org.apache.sshd.client.session.ClientSession import org.apache.sshd.client.session.ClientSession
@@ -51,8 +53,7 @@ class HostDialog(owner: Window, host: Host? = null) : DialogWrapper(owner) {
putValue(NAME, "${I18n.getString("termora.new-host.test-connection")}...") putValue(NAME, "${I18n.getString("termora.new-host.test-connection")}...")
isEnabled = false isEnabled = false
@OptIn(DelicateCoroutinesApi::class) swingCoroutineScope.launch(Dispatchers.IO) {
GlobalScope.launch(Dispatchers.IO) {
testConnection(pane.getHost()) testConnection(pane.getHost())
withContext(Dispatchers.Swing) { withContext(Dispatchers.Swing) {
putValue(NAME, I18n.getString("termora.new-host.test-connection")) putValue(NAME, I18n.getString("termora.new-host.test-connection"))

View File

@@ -10,7 +10,6 @@ import com.formdev.flatlaf.util.SystemInfo
import com.jgoodies.forms.builder.FormBuilder import com.jgoodies.forms.builder.FormBuilder
import com.jgoodies.forms.layout.FormLayout import com.jgoodies.forms.layout.FormLayout
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@@ -1123,8 +1122,7 @@ open class HostOptionsPane : OptionsPane() {
addComponentListener(object : ComponentAdapter() { addComponentListener(object : ComponentAdapter() {
override fun componentShown(e: ComponentEvent) { override fun componentShown(e: ComponentEvent) {
removeComponentListener(this) removeComponentListener(this)
@Suppress("OPT_IN_USAGE") swingCoroutineScope.launch(Dispatchers.IO) {
GlobalScope.launch(Dispatchers.IO) {
for (commPort in SerialPort.getCommPorts()) { for (commPort in SerialPort.getCommPorts()) {
withContext(Dispatchers.Swing) { withContext(Dispatchers.Swing) {
serialPortComboBox.addItem(commPort.systemPortName) serialPortComboBox.addItem(commPort.systemPortName)

View File

@@ -5,7 +5,9 @@ import com.formdev.flatlaf.FlatClientProperties
import com.formdev.flatlaf.extras.components.FlatTextPane import com.formdev.flatlaf.extras.components.FlatTextPane
import com.formdev.flatlaf.util.SystemInfo import com.formdev.flatlaf.util.SystemInfo
import com.jetbrains.JBR import com.jetbrains.JBR
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import org.apache.commons.lang3.StringUtils import org.apache.commons.lang3.StringUtils
import java.awt.BorderLayout import java.awt.BorderLayout
@@ -20,6 +22,8 @@ import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
object OptionPane { object OptionPane {
private val coroutineScope = swingCoroutineScope
fun showConfirmDialog( fun showConfirmDialog(
parentComponent: Component?, parentComponent: Component?,
message: Any, message: Any,
@@ -104,9 +108,8 @@ object OptionPane {
val dialog = initDialog(pane.createDialog(parentComponent, title)) val dialog = initDialog(pane.createDialog(parentComponent, title))
if (duration.inWholeMilliseconds > 0) { if (duration.inWholeMilliseconds > 0) {
dialog.addWindowListener(object : WindowAdapter() { dialog.addWindowListener(object : WindowAdapter() {
@OptIn(DelicateCoroutinesApi::class)
override fun windowOpened(e: WindowEvent) { override fun windowOpened(e: WindowEvent) {
GlobalScope.launch(Dispatchers.Swing) { coroutineScope.launch(Dispatchers.Swing) {
delay(duration.inWholeMilliseconds) delay(duration.inWholeMilliseconds)
if (dialog.isVisible) { if (dialog.isVisible) {
dialog.isVisible = false dialog.isVisible = false

View File

@@ -1,5 +1,10 @@
package app.termora package app.termora
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.swing.Swing
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.awt.Component import java.awt.Component
import java.awt.Window import java.awt.Window
@@ -8,6 +13,8 @@ import javax.swing.JPopupMenu
import javax.swing.SwingUtilities import javax.swing.SwingUtilities
import kotlin.reflect.KClass import kotlin.reflect.KClass
val swingCoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Swing)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
open class Scope( open class Scope(
private val beans: MutableMap<KClass<*>, Any> = ConcurrentHashMap(), private val beans: MutableMap<KClass<*>, Any> = ConcurrentHashMap(),
@@ -151,6 +158,7 @@ class ApplicationScope private constructor() : Scope() {
if (log.isInfoEnabled) { if (log.isInfoEnabled) {
log.info("ApplicationScope disposed") log.info("ApplicationScope disposed")
} }
swingCoroutineScope.cancel()
super.dispose() super.dispose()
} }

View File

@@ -36,8 +36,10 @@ import com.jgoodies.forms.builder.FormBuilder
import com.jgoodies.forms.layout.FormLayout import com.jgoodies.forms.layout.FormLayout
import com.jthemedetecor.OsThemeDetector import com.jthemedetecor.OsThemeDetector
import com.sun.jna.LastErrorException import com.sun.jna.LastErrorException
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.* import kotlinx.serialization.json.*
import org.apache.commons.codec.binary.Base64 import org.apache.commons.codec.binary.Base64
import org.apache.commons.io.IOUtils import org.apache.commons.io.IOUtils
@@ -615,10 +617,9 @@ class SettingsOptionsPane : OptionsPane() {
add(getCenterComponent(), BorderLayout.CENTER) add(getCenterComponent(), BorderLayout.CENTER)
} }
@OptIn(DelicateCoroutinesApi::class)
private fun initEvents() { private fun initEvents() {
syncConfigButton.addActionListener { syncConfigButton.addActionListener {
GlobalScope.launch(Dispatchers.IO) { sync() } swingCoroutineScope.launch(Dispatchers.IO) { sync() }
} }
typeComboBox.addItemListener { typeComboBox.addItemListener {

View File

@@ -4,7 +4,6 @@ import com.formdev.flatlaf.FlatLaf
import com.formdev.flatlaf.extras.FlatAnimatedLafChange import com.formdev.flatlaf.extras.FlatAnimatedLafChange
import com.jthemedetecor.OsThemeDetector import com.jthemedetecor.OsThemeDetector
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.util.* import java.util.*
@@ -76,8 +75,7 @@ class ThemeManager private constructor() {
init { init {
@Suppress("OPT_IN_USAGE") swingCoroutineScope.launch(Dispatchers.IO) {
GlobalScope.launch(Dispatchers.IO) {
OsThemeDetector.getDetector().registerListener(object : Consumer<Boolean> { OsThemeDetector.getDetector().registerListener(object : Consumer<Boolean> {
override fun accept(isDark: Boolean) { override fun accept(isDark: Boolean) {
if (!appearance.followSystem) { if (!appearance.followSystem) {

View File

@@ -36,6 +36,7 @@ class AppUpdateAction private constructor() : AnAction(
StringUtils.EMPTY, StringUtils.EMPTY,
Icons.ideUpdate Icons.ideUpdate
) { ) {
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Swing)
companion object { companion object {
private val log = LoggerFactory.getLogger(AppUpdateAction::class.java) private val log = LoggerFactory.getLogger(AppUpdateAction::class.java)
@@ -59,7 +60,6 @@ class AppUpdateAction private constructor() : AnAction(
} }
@OptIn(DelicateCoroutinesApi::class)
private fun scheduleUpdate() { private fun scheduleUpdate() {
fixedRateTimer( fixedRateTimer(
name = "check-update-timer", name = "check-update-timer",
@@ -67,7 +67,7 @@ class AppUpdateAction private constructor() : AnAction(
period = 5.hours.inWholeMilliseconds, daemon = true period = 5.hours.inWholeMilliseconds, daemon = true
) { ) {
if (!isRemindMeNextTime) { if (!isRemindMeNextTime) {
GlobalScope.launch(Dispatchers.IO) { supervisorScope { launch { checkUpdate() } } } coroutineScope.launch(Dispatchers.IO) { checkUpdate() }
} }
} }
} }

View File

@@ -3,8 +3,11 @@ package app.termora.terminal.panel
import app.termora.Database import app.termora.Database
import app.termora.DynamicColor import app.termora.DynamicColor
import app.termora.assertEventDispatchThread import app.termora.assertEventDispatchThread
import app.termora.swingCoroutineScope
import app.termora.terminal.* import app.termora.terminal.*
import kotlinx.coroutines.* import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.swing.Swing import kotlinx.coroutines.swing.Swing
import java.awt.* import java.awt.*
import javax.swing.JComponent import javax.swing.JComponent
@@ -484,14 +487,13 @@ class TerminalDisplay(
g.font = font g.font = font
} }
@OptIn(DelicateCoroutinesApi::class)
fun toast(text: String, duration: Duration) { fun toast(text: String, duration: Duration) {
if (!terminalPanel.showToast) { if (!terminalPanel.showToast) {
return return
} }
val toast = Toast(text) val toast = Toast(text)
GlobalScope.launch(Dispatchers.Swing) { swingCoroutineScope.launch(Dispatchers.Swing) {
delay(duration) delay(duration)
toasts.remove(toast) toasts.remove(toast)
terminalPanel.repaintImmediate() terminalPanel.repaintImmediate()