mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[rdct] IJPL-196175 IJPL-202195: Use invisible modality if the file is opened in the modal progress
If the file is opened on EDT under the modal progress, the race could happen between modal progress's UI and `blockingWaitForCompositeFileOpen`: 1. `blockingWaitForCompositeFileOpen` starts with already showing modal progress dialog 2. The pumping inside the function wants to pump the modal dialog and check after it if the initialization job is done 3. The modal dialog waits until all its subroutines (including one that pumps EDT) are finished, thus the EDT will never be pumped. This bug is similar to the IDEA-319932, where navigation was done under the write action. However, in this case there's no write action, but just Dialog's UI. The fix is to wait under the new modality: 1. If the original modal's UI is not shown, it will be not shown, since it requires a lower modality to show, so no infinite dialog's event 2. If the original modal's UI has been already shown, `pumpEventsForHierarchy` should pump the correct queue GitOrigin-RevId: bd513ec3936118ca0fd03a42f100dc7763669adf
This commit is contained in:
committed by
intellij-monorepo-bot
parent
837bf09c88
commit
c27f72b43e
+28
-13
@@ -21,6 +21,8 @@ import com.intellij.openapi.actionSystem.IdeActions
|
||||
import com.intellij.openapi.application.*
|
||||
import com.intellij.openapi.application.impl.ApplicationImpl
|
||||
import com.intellij.openapi.application.impl.InternalUICustomization
|
||||
import com.intellij.openapi.application.impl.LaterInvocator
|
||||
import com.intellij.openapi.application.impl.inModalContext
|
||||
import com.intellij.openapi.client.ClientKind
|
||||
import com.intellij.openapi.client.currentSessionOrNull
|
||||
import com.intellij.openapi.components.*
|
||||
@@ -82,6 +84,7 @@ import com.intellij.ui.docking.impl.DockManagerImpl
|
||||
import com.intellij.ui.tabs.TabInfo
|
||||
import com.intellij.util.ExceptionUtil
|
||||
import com.intellij.util.IconUtil
|
||||
import com.intellij.util.ObjectUtils
|
||||
import com.intellij.util.PlatformUtils
|
||||
import com.intellij.util.concurrency.ThreadingAssertions
|
||||
import com.intellij.util.concurrency.annotations.RequiresEdt
|
||||
@@ -2486,6 +2489,7 @@ fun blockingWaitForCompositeFileOpen(composite: EditorComposite) {
|
||||
|
||||
// https://youtrack.jetbrains.com/issue/IDEA-319932
|
||||
// runWithModalProgressBlocking cannot be used under a write action - https://youtrack.jetbrains.com/issue/IDEA-319932
|
||||
// IJPL-196175 & IJPL-202195: `pumpEventsForHierarchy` can't be used within `runWithModalProgressBlocking`
|
||||
if (ApplicationManager.getApplication().isWriteAccessAllowed) {
|
||||
// todo silenceWriteLock instead of executeSuspendingWriteAction
|
||||
(ApplicationManager.getApplication() as ApplicationImpl).executeSuspendingWriteAction(
|
||||
@@ -2497,23 +2501,34 @@ fun blockingWaitForCompositeFileOpen(composite: EditorComposite) {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (LaterInvocator.isInModalContext()) {
|
||||
inModalContext(ObjectUtils.sentinel("Opening file=${composite.file.name}")) {
|
||||
job.waitBlockingAndPumpEdt()
|
||||
}
|
||||
}
|
||||
else {
|
||||
// we don't need progress - handled by async editor loader
|
||||
val (parallelizedLockContext, cleanup) = getGlobalThreadingSupport().getPermitAsContextElement(currentThreadContext(), true)
|
||||
try {
|
||||
runBlocking(parallelizedLockContext) {
|
||||
job.invokeOnCompletion {
|
||||
EventQueue.invokeLater(EmptyRunnable.getInstance())
|
||||
}
|
||||
IdeEventQueue.getInstance().pumpEventsForHierarchy {
|
||||
job.isCompleted
|
||||
}
|
||||
job.join()
|
||||
job.waitBlockingAndPumpEdt()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("RAW_RUN_BLOCKING")
|
||||
@RequiresEdt
|
||||
private fun Job.waitBlockingAndPumpEdt() {
|
||||
val (parallelizedLockContext, cleanup) = getGlobalThreadingSupport().getPermitAsContextElement(currentThreadContext(), true)
|
||||
try {
|
||||
runBlocking(parallelizedLockContext) {
|
||||
invokeOnCompletion {
|
||||
EventQueue.invokeLater(EmptyRunnable.getInstance())
|
||||
}
|
||||
|
||||
IdeEventQueue.getInstance().pumpEventsForHierarchy {
|
||||
isCompleted
|
||||
}
|
||||
}
|
||||
finally {
|
||||
cleanup()
|
||||
}
|
||||
}
|
||||
finally {
|
||||
cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user