mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 18:05:27 +07:00
IJPL-196231 Fix launch(Once)OnShow for unconfined coroutines
Dispatchers.Unconfined doesn't immediately invoke the coroutine if already running an unconfined coroutine. If the current coroutine is blocked on dialog.show(), it means that no unconfined jobs will be executed while the dialog is showing. To work around it, we replace Dispatchers.Unconfined with the appropriate UI dispatcher that is guaranteed to not dispatch if used with any() modality. Implement the fix under a registry key, disabled for now, so we can safely pick it to the release branches to have this as a possible manual fallback for the users who experience this issue. Reviewed in IJ-CR-168711 for 252 and release. (cherry picked from commit 3cfd1a9e46d12d942c7ab6f30f158b71cd7e52d8) GitOrigin-RevId: c700503bf1f2c328d4be4eb088210a6deed536de
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c95451c5d7
commit
26b320e5d1
@@ -1,10 +1,8 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.util.ui
|
||||
|
||||
import com.intellij.openapi.application.AccessToken
|
||||
import com.intellij.openapi.application.ModalityState
|
||||
import com.intellij.openapi.application.UI
|
||||
import com.intellij.openapi.application.asContextElement
|
||||
import com.intellij.openapi.application.*
|
||||
import com.intellij.openapi.util.registry.Registry
|
||||
import com.intellij.platform.kernel.withKernel
|
||||
import com.intellij.ui.ComponentUtil
|
||||
import com.intellij.util.BitUtil
|
||||
@@ -155,11 +153,30 @@ fun <C : Component> C.launchOnShow(
|
||||
* Launches the given task in the global scope without dispatching.
|
||||
*/
|
||||
private fun launchUnconfined(debugName: String, block: suspend CoroutineScope.() -> Unit): Job {
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
return GlobalScope.launch(
|
||||
context = Dispatchers.Unconfined + CoroutineName(debugName),
|
||||
block = block,
|
||||
)
|
||||
if (Registry.`is`("ide.ui.coroutine.scopes.unconfined.fix", false)) {
|
||||
// The whole point here is to launch the coroutine in-place without dispatching,
|
||||
// and to make sure it doesn't dispatch later when called on the EDT from the hierarchy listener.
|
||||
// This is why Dispatchers.ui(UiDispatcherKind.RELAX, immediate = true) is used with ModalityState.any().
|
||||
// The modality is obvious: using any() ensures that the current modality is ignored when processing hierarchy events.
|
||||
// The task itself will then check the modality before executing, but events should be processed immediately.
|
||||
// The dispatcher is a bit more tricky: using EDT will dispatch if the WIL is forbidden (when already running under UI),
|
||||
// and using UI will dispatch if the WIL is currently locked.
|
||||
// But RELAX doesn't care about the WIL and whether it's allowed, so it will not dispatch if immediate = true.
|
||||
// Note that using Dispatchers.Unconfined here seems the obvious choice,
|
||||
// but it doesn't work when already running an unconfined coroutine (IJPL-196231, CPP-45385).
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
return GlobalScope.launch(
|
||||
context = Dispatchers.ui(UiDispatcherKind.RELAX, immediate = true) + ModalityState.any().asContextElement() + CoroutineName(debugName),
|
||||
block = block,
|
||||
)
|
||||
}
|
||||
else {
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
return GlobalScope.launch(
|
||||
context = Dispatchers.Unconfined + CoroutineName(debugName),
|
||||
block = block,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun showingAsChannel(component: Component, block: suspend (ReceiveChannel<Boolean>) -> Unit) {
|
||||
|
||||
@@ -2507,6 +2507,9 @@ coroutine.scope.model.description=Use the new experimental coroutine-based model
|
||||
ide.treat.project.modality.as.application=true
|
||||
ide.treat.project.modality.as.application.description=Treat DialogWrapper.IdeModalityType.PROJECT as Dialog.ModalityType.APPLICATION_MODAL
|
||||
|
||||
ide.ui.coroutine.scopes.unconfined.fix=false
|
||||
ide.ui.coroutine.scopes.unconfined.fix.description=Enable the fix for launchOnShow/launchOnceOnShow issue that prevented these from working in modal dialogs sometimes.
|
||||
|
||||
editor.show.sticky.lines.debug=false
|
||||
editor.show.sticky.lines.debug.description=Show editor sticky lines in debug mode
|
||||
editor.show.sticky.lines.shadow=true
|
||||
|
||||
Reference in New Issue
Block a user