From 184812fb0d44072b365bceec709be32af3c25a36 Mon Sep 17 00:00:00 2001 From: Vladimir Krivosheev Date: Thu, 11 Jul 2024 13:23:29 +0200 Subject: [PATCH] IJPL-158075 use flow instead of deprecated alarm for moveOrResizeRequests GitOrigin-RevId: af5833e031fb27e379f1bc4dd558fd522ad6bd6c --- platform/ide-core/api-dump-unreviewed.txt | 6 +- platform/lang-impl/api-dump-unreviewed.txt | 2 +- .../openapi/wm/impl/FloatingDecorator.java | 6 +- .../openapi/wm/impl/ToolWindowImpl.kt | 74 ++++++++++++------- .../wm/impl/content/ToolWindowContentUi.java | 8 +- 5 files changed, 58 insertions(+), 38 deletions(-) diff --git a/platform/ide-core/api-dump-unreviewed.txt b/platform/ide-core/api-dump-unreviewed.txt index adfda9f1b53b..e517d168c346 100644 --- a/platform/ide-core/api-dump-unreviewed.txt +++ b/platform/ide-core/api-dump-unreviewed.txt @@ -2985,7 +2985,8 @@ f:com.intellij.util.SingleAlarm - (java.lang.Runnable,I,com.intellij.openapi.Disposable):V - (java.lang.Runnable,I,com.intellij.openapi.Disposable,com.intellij.util.Alarm$ThreadToUse):V - (java.lang.Runnable,I,com.intellij.openapi.Disposable,com.intellij.util.Alarm$ThreadToUse,com.intellij.openapi.application.ModalityState):V -- b:(java.lang.Runnable,I,com.intellij.openapi.Disposable,com.intellij.util.Alarm$ThreadToUse,com.intellij.openapi.application.ModalityState,I,kotlin.jvm.internal.DefaultConstructorMarker):V +- (java.lang.Runnable,I,com.intellij.openapi.Disposable,com.intellij.util.Alarm$ThreadToUse,com.intellij.openapi.application.ModalityState,kotlinx.coroutines.CoroutineScope):V +- b:(java.lang.Runnable,I,com.intellij.openapi.Disposable,com.intellij.util.Alarm$ThreadToUse,com.intellij.openapi.application.ModalityState,kotlinx.coroutines.CoroutineScope,I,kotlin.jvm.internal.DefaultConstructorMarker):V - (java.lang.Runnable,I,com.intellij.util.Alarm$ThreadToUse,com.intellij.openapi.Disposable):V - f:cancel():V - f:cancelAllRequests():I @@ -2996,13 +2997,14 @@ f:com.intellij.util.SingleAlarm - f:isDisposed():Z - f:isEmpty():Z - f:request():V -- f:request(com.intellij.openapi.application.ModalityState):V - f:request(Z):V - f:request(Z,I):V - bs:request$default(com.intellij.util.SingleAlarm,Z,I,I,java.lang.Object):V +- sf:singleAlarm(I,kotlinx.coroutines.CoroutineScope,java.lang.Runnable):com.intellij.util.SingleAlarm - f:waitForAllExecuted(J,java.util.concurrent.TimeUnit):V f:com.intellij.util.SingleAlarm$Companion - f:pooledThreadSingleAlarm(I,com.intellij.openapi.Disposable,kotlin.jvm.functions.Function0):com.intellij.util.SingleAlarm +- f:singleAlarm(I,kotlinx.coroutines.CoroutineScope,java.lang.Runnable):com.intellij.util.SingleAlarm f:com.intellij.util.WaitForProgressToShow - s:execute(com.intellij.openapi.progress.ProgressIndicator):V - s:runOrInvokeAndWaitAboveProgress(java.lang.Runnable):V diff --git a/platform/lang-impl/api-dump-unreviewed.txt b/platform/lang-impl/api-dump-unreviewed.txt index b8dcae94a21d..6f3ec4ae3aaa 100644 --- a/platform/lang-impl/api-dump-unreviewed.txt +++ b/platform/lang-impl/api-dump-unreviewed.txt @@ -12713,7 +12713,7 @@ a:com.intellij.ide.GeneratedSourceFileChangeTracker f:com.intellij.ide.GeneratedSourceFileChangeTrackerImpl - com.intellij.ide.GeneratedSourceFileChangeTracker - s:IN_TRACKER_TEST:Z -- (com.intellij.openapi.project.Project):V +- (com.intellij.openapi.project.Project,kotlinx.coroutines.CoroutineScope):V - cancelAllAndWait(J,java.util.concurrent.TimeUnit):V - isEditedGeneratedFile(com.intellij.openapi.vfs.VirtualFile):Z f:com.intellij.ide.NativeIconProvider diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java index cdfd3f28561b..b7beeecc429f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FloatingDecorator.java @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.wm.impl; import com.intellij.ide.ui.UISettings; @@ -89,8 +89,8 @@ public final class FloatingDecorator extends JDialog implements FloatingDecorato if (LOG.isDebugEnabled()) { LOG.debug("Updating floating window " + toolWindow.getId() + " bounds because it's closed: " + getBounds()); } - toolWindow.getToolWindowManager().movedOrResized(decorator); - toolWindow.getToolWindowManager().hideToolWindow(toolWindow.getId(), false); + toolWindow.toolWindowManager.movedOrResized(decorator); + toolWindow.toolWindowManager.hideToolWindow(toolWindow.getId(), false); } }); addComponentListener(new ComponentAdapter() { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt index 453bfde82940..e10e002c93ac 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowImpl.kt @@ -1,4 +1,6 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +@file:OptIn(FlowPreview::class) + package com.intellij.openapi.wm.impl import com.intellij.icons.AllIcons @@ -17,6 +19,7 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.actionSystem.* import com.intellij.openapi.actionSystem.ex.ActionUtil import com.intellij.openapi.actionSystem.impl.FusAwareAction +import com.intellij.openapi.application.EDT import com.intellij.openapi.application.ModalityState import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.diagnostic.logger @@ -44,12 +47,21 @@ import com.intellij.ui.scale.JBUIScale import com.intellij.util.ArrayUtil import com.intellij.util.ModalityUiUtil import com.intellij.util.SingleAlarm +import com.intellij.util.cancelOnDispose import com.intellij.util.concurrency.SynchronizedClearableLazy import com.intellij.util.ui.* import com.intellij.util.ui.update.Activatable import com.intellij.util.ui.update.UiNotifyConnector import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.persistentListOf +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.FlowPreview +import kotlinx.coroutines.channels.BufferOverflow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.jetbrains.annotations.ApiStatus import java.awt.AWTEvent import java.awt.Color @@ -62,16 +74,18 @@ import java.util.function.Supplier import javax.swing.* import kotlin.math.abs -internal class ToolWindowImpl(val toolWindowManager: ToolWindowManagerImpl, - private val id: String, - private val canCloseContent: Boolean, - private val dumbAware: Boolean, - component: JComponent?, - private val parentDisposable: Disposable, - windowInfo: WindowInfo, - private var contentFactory: ToolWindowFactory?, - private var isAvailable: Boolean = true, - private var stripeTitleProvider: Supplier<@NlsContexts.TabTitle String>) : ToolWindowEx { +internal class ToolWindowImpl( + @JvmField val toolWindowManager: ToolWindowManagerImpl, + private val id: String, + private val canCloseContent: Boolean, + private val dumbAware: Boolean, + component: JComponent?, + private val parentDisposable: Disposable, + windowInfo: WindowInfo, + private var contentFactory: ToolWindowFactory?, + private var isAvailable: Boolean = true, + private var stripeTitleProvider: Supplier<@NlsContexts.TabTitle String>, +) : ToolWindowEx { @JvmField var windowInfoDuringInit: WindowInfoImpl? = null @@ -119,25 +133,12 @@ internal class ToolWindowImpl(val toolWindowManager: ToolWindowManagerImpl, private val contentManager = SynchronizedClearableLazy { val result = createContentManager() if (toolWindowManager.isNewUi) { - result.addContentManagerListener(UpdateBackgroundContentManager(decorator)) + result.addContentManagerListener(UpdateBackgroundContentManager()) } result } - private val moveOrResizeAlarm = SingleAlarm( - task = Runnable { - val decorator = decorator - if (decorator != null) { - toolWindowManager.log().debug { "Invoking scheduled tool window $id bounds update" } - toolWindowManager.movedOrResized(decorator) - } - val updatedWindowInfo = toolWindowManager.getLayout().getInfo(getId()) as WindowInfo - this@ToolWindowImpl.windowInfo = updatedWindowInfo - toolWindowManager.log().debug { "Updated window info: $updatedWindowInfo" } - }, - delay = 100, - parentDisposable = disposable, - ) + private val moveOrResizeRequests = MutableSharedFlow(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST) init { if (component != null) { @@ -146,9 +147,26 @@ internal class ToolWindowImpl(val toolWindowManager: ToolWindowManagerImpl, contentManager.addContent(content) contentManager.setSelectedContent(content, false) } + + toolWindowManager.coroutineScope.launch { + moveOrResizeRequests + .debounce(100) + .collectLatest { + withContext(Dispatchers.EDT) { + val decorator = decorator + if (decorator != null) { + toolWindowManager.log().debug { "Invoking scheduled tool window $id bounds update" } + toolWindowManager.movedOrResized(decorator) + } + val updatedWindowInfo = toolWindowManager.getLayout().getInfo(getId()) as WindowInfo + this@ToolWindowImpl.windowInfo = updatedWindowInfo + toolWindowManager.log().debug { "Updated window info: $updatedWindowInfo" } + } + } + }.cancelOnDispose(disposable) } - private class UpdateBackgroundContentManager(private val decorator: InternalDecoratorImpl?) : ContentManagerListener { + private class UpdateBackgroundContentManager() : ContentManagerListener { override fun contentAdded(event: ContentManagerEvent) { InternalDecoratorImpl.setBackgroundRecursively(event.content.component, JBUI.CurrentTheme.ToolWindow.background()) } @@ -210,7 +228,7 @@ internal class ToolWindowImpl(val toolWindowManager: ToolWindowManagerImpl, override fun unprocessComponent(component: Component) = Unit }.register(decorator) if (ExperimentalUI.isNewUI()) { - scrollPaneTracker = ScrollPaneTracker(decorator, { true }) { + scrollPaneTracker = ScrollPaneTracker(container = decorator, filter = { true }) { updateScrolledState() } } @@ -310,7 +328,7 @@ internal class ToolWindowImpl(val toolWindowManager: ToolWindowManagerImpl, } fun onMovedOrResized() { - moveOrResizeAlarm.cancelAndRequest() + check(moveOrResizeRequests.tryEmit(Unit)) } internal fun setWindowInfoSilently(info: WindowInfo) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ToolWindowContentUi.java b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ToolWindowContentUi.java index 0588b082f332..42fa8cfc0971 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ToolWindowContentUi.java +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/content/ToolWindowContentUi.java @@ -156,7 +156,7 @@ public final class ToolWindowContentUi implements ContentUI, UiCompatibleDataPro @Override public void contentRemoved(@NotNull ContentManagerEvent event) { - if (window.isDisposed() || window.getToolWindowManager().getProject().isDisposed()) { + if (window.isDisposed() || window.toolWindowManager.getProject().isDisposed()) { return; } @@ -183,7 +183,7 @@ public final class ToolWindowContentUi implements ContentUI, UiCompatibleDataPro else { return; } - window.getToolWindowManager() + window.toolWindowManager .hideToolWindow(window.getId(), /* hideSide = */ false, /* moveFocus = */ true, removeFromStripe, /* source = */ null); } } @@ -268,7 +268,7 @@ public final class ToolWindowContentUi implements ContentUI, UiCompatibleDataPro return false; } - ToolWindowManagerImpl manager = window.getToolWindowManager(); + ToolWindowManagerImpl manager = window.toolWindowManager; for (String id : manager.getIdsOn(window.getAnchor())) { if (id.equals(window.getId())) { continue; @@ -699,7 +699,7 @@ public final class ToolWindowContentUi implements ContentUI, UiCompatibleDataPro public void uiDataSnapshot(@NotNull DataSink sink) { sink.set(PlatformDataKeys.TOOL_WINDOW, window); sink.set(PlatformCoreDataKeys.HELP_ID, window.getHelpId()); - sink.set(CommonDataKeys.PROJECT, window.getToolWindowManager().getProject()); + sink.set(CommonDataKeys.PROJECT, window.toolWindowManager.getProject()); sink.set(CloseAction.CloseTarget.KEY, computeCloseTarget()); if (getCurrentLayout() instanceof MorePopupAware o) { sink.set(MorePopupAware.KEY_TOOLWINDOW_TITLE, o);