diff --git a/platform/platform-api/src/com/intellij/openapi/wm/WindowManager.java b/platform/platform-api/src/com/intellij/openapi/wm/WindowManager.java index 3c1bdda494e2..a4e6d278e0d0 100644 --- a/platform/platform-api/src/com/intellij/openapi/wm/WindowManager.java +++ b/platform/platform-api/src/com/intellij/openapi/wm/WindowManager.java @@ -96,4 +96,7 @@ public abstract class WindowManager { public abstract boolean isFullScreenSupportedInCurrentOS(); public abstract void requestUserAttention(@NotNull IdeFrame frame, boolean critical); + + public void updateDefaultFrameInfoOnProjectClose(@NotNull Project project) { + } } diff --git a/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.kt b/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.kt index cd2ccdc09e37..b701526c4a64 100644 --- a/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.kt +++ b/platform/platform-impl/src/com/intellij/ide/RecentProjectsManagerBase.kt @@ -16,7 +16,9 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager import com.intellij.openapi.project.ProjectManagerListener import com.intellij.openapi.project.ex.ProjectManagerEx -import com.intellij.openapi.project.impl.* +import com.intellij.openapi.project.impl.ProjectUiFrameAllocator +import com.intellij.openapi.project.impl.ProjectUiFrameManager +import com.intellij.openapi.project.impl.createNewProjectFrame import com.intellij.openapi.startup.StartupManager import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.SystemInfo @@ -275,7 +277,9 @@ open class RecentProjectsManagerBase : RecentProjectsManager(), PersistentStateC val appInfo = ApplicationInfoEx.getInstanceEx() info.displayName = getProjectDisplayName(project) info.projectWorkspaceId = project.stateStore.projectWorkspaceId - info.frame = ProjectFrameBounds.getInstance(project).frameInfoHelper.info + ProjectFrameBounds.getInstance(project).frameInfoHelper.info?.let { + info.frame = it + } info.build = appInfo!!.build.asString() info.productionCode = appInfo.build.productCode info.eap = appInfo.isEAP @@ -538,11 +542,15 @@ open class RecentProjectsManagerBase : RecentProjectsManager(), PersistentStateC LOG.warn("Cannot find frameHelper for ${project.name} to update frame info") return } + val frame = frameHelper.frame + if (frame == null) { + LOG.warn("frameHelper.frame is null, cannot ${project.name} to update frame info") + return + } val workspaceId = project.stateStore.projectWorkspaceId - // ensure that last closed project frame bounds will be used as newly created project frame bounds (if will be no another focused opened project) - val frameInfo = ProjectFrameBounds.getInstance(project).getActualFrameInfoInDeviceSpace(frameHelper, windowManager) + val frameInfo = ProjectFrameBounds.getInstance(project).getActualFrameInfoInDeviceSpace(frameHelper, frame, windowManager) val path = getProjectPath(project) synchronized(stateLock) { val info = state.additionalInfo.get(path) @@ -554,13 +562,13 @@ open class RecentProjectsManagerBase : RecentProjectsManager(), PersistentStateC info.frame = frameInfo } info.projectWorkspaceId = workspaceId - info.frameTitle = frameHelper.frame?.title + info.frameTitle = frame.title } } LOG.runAndLogException { if (writLastProjectInfo) { - writeInfoFile(frameInfo, frameHelper.frame ?: return@runAndLogException) + writeInfoFile(frameInfo, frame) } if (workspaceId != null && Registry.`is`("ide.project.loading.show.last.state")) { diff --git a/platform/platform-impl/src/com/intellij/ide/actions/CloseProjectAction.java b/platform/platform-impl/src/com/intellij/ide/actions/CloseProjectAction.java index c44f426bf4cb..06d8b8f87320 100644 --- a/platform/platform-impl/src/com/intellij/ide/actions/CloseProjectAction.java +++ b/platform/platform-impl/src/com/intellij/ide/actions/CloseProjectAction.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ide.actions; import com.intellij.ide.IdeBundle; @@ -11,7 +11,7 @@ import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.DumbAware; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ex.ProjectManagerEx; -import com.intellij.openapi.wm.impl.ProjectFrameBounds; +import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.impl.welcomeScreen.WelcomeFrame; import com.intellij.projectImport.ProjectAttachProcessor; import com.intellij.ui.IdeUICustomization; @@ -28,7 +28,7 @@ public final class CloseProjectAction extends AnAction implements DumbAware { assert project != null; // ensure that last closed project frame bounds will be used as newly created project frame bounds (if will be no another focused opened project) - ProjectFrameBounds.getInstance(project).updateDefaultFrameInfoOnProjectClose(); + WindowManager.getInstance().updateDefaultFrameInfoOnProjectClose(project); ProjectManagerEx.getInstanceEx().closeAndDispose(project); // RecentProjectsManager cannot distinguish close as part of exit (no need to remove project), diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FrameInfoHelper.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FrameInfoHelper.kt index 13d14acb7262..97915a94a64d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/FrameInfoHelper.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/FrameInfoHelper.kt @@ -14,6 +14,7 @@ import java.awt.Point import java.awt.Rectangle import java.awt.peer.ComponentPeer import java.awt.peer.FramePeer +import javax.swing.JFrame internal class FrameInfoHelper { companion object { @@ -43,26 +44,28 @@ internal class FrameInfoHelper { this.info = info } - fun updateFrameInfo(frame: ProjectFrameHelper) { - info = updateFrameInfo(frame, null, info) + fun updateFrameInfo(frameHelper: ProjectFrameHelper, frame: JFrame) { + info = updateFrameInfo(frameHelper, frame, null, info) } fun getModificationCount(): Long { return info?.modificationCount ?: 0 } - fun updateAndGetModificationCount(project: Project, lastNormalFrameBounds: Rectangle?, windowManager: WindowManagerImpl): Long { - val frame = windowManager.getFrameHelper(project) ?: return getModificationCount() - return updateAndGetModificationCount(frame, lastNormalFrameBounds, windowManager) + fun update(project: Project, lastNormalFrameBounds: Rectangle?, windowManager: WindowManagerImpl) { + val frameHelper = windowManager.getFrameHelper(project) ?: return + updateAndGetInfo(frameHelper, frameHelper.frame ?: return, lastNormalFrameBounds, windowManager) } - fun updateAndGetModificationCount(frame: ProjectFrameHelper, lastNormalFrameBounds: Rectangle?, windowManager: WindowManagerImpl): Long { - val newInfo = updateFrameInfo(frame, lastNormalFrameBounds, info) - updateDefaultFrameInfoInDeviceSpace(windowManager, newInfo) + fun updateAndGetInfo(frameHelper: ProjectFrameHelper, + frame: JFrame, + lastNormalFrameBounds: Rectangle?, + windowManager: WindowManagerImpl): FrameInfo { + val newInfo = updateFrameInfo(frameHelper, frame, lastNormalFrameBounds, info) + windowManager.defaultFrameInfoHelper.copyFrom(newInfo) info = newInfo - isDirty = false - return getModificationCount() + return newInfo } fun copyFrom(newInfo: FrameInfo) { @@ -74,8 +77,7 @@ internal class FrameInfoHelper { } } -private fun updateFrameInfo(frameHelper: ProjectFrameHelper, lastNormalFrameBounds: Rectangle?, oldFrameInfo: FrameInfo?): FrameInfo { - val frame = frameHelper.frame!! +internal fun updateFrameInfo(frameHelper: ProjectFrameHelper, frame: JFrame, lastNormalFrameBounds: Rectangle?, oldFrameInfo: FrameInfo?): FrameInfo { var extendedState = frame.extendedState if (SystemInfoRt.isMac) { // java 11 @@ -112,9 +114,4 @@ private fun updateFrameInfo(frameHelper: ProjectFrameHelper, lastNormalFrameBoun frameInfo.fullScreen = isInFullScreen } return frameInfo -} - -internal fun updateDefaultFrameInfoInDeviceSpace(windowManager: WindowManagerImpl, newInfo: FrameInfo) { - // see comment in the myFrameStateListener about chicken and egg problem - windowManager.defaultFrameInfoHelper.copyFrom(newInfo) } \ No newline at end of file diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ProjectFrameBounds.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ProjectFrameBounds.kt index 8cb67f9d512b..af1195f0634f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ProjectFrameBounds.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ProjectFrameBounds.kt @@ -5,14 +5,14 @@ import com.intellij.openapi.components.BaseState import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.project.Project -import com.intellij.openapi.wm.WindowManager import com.intellij.util.xmlb.annotations.Property import com.intellij.util.xmlb.annotations.Tag import java.awt.Frame import java.awt.Rectangle +import javax.swing.JFrame @Service -class ProjectFrameBounds(private val project: Project) { +internal class ProjectFrameBounds { companion object { @JvmStatic fun getInstance(project: Project) = project.service() @@ -21,29 +21,8 @@ class ProjectFrameBounds(private val project: Project) { internal val frameInfoHelper = FrameInfoHelper() private var pendingBounds: Rectangle? = null - /** - * Maybe outdated. You must always check isDirty if you need actual info. - */ - internal fun getFrameInfoInDeviceSpace() = frameInfoHelper.info - - internal fun getActualFrameInfoInDeviceSpace(frame: ProjectFrameHelper, windowManager: WindowManagerImpl): FrameInfo { - val result = frameInfoHelper.info - if (frameInfoHelper.isDirty || result == null) { - frameInfoHelper.updateAndGetModificationCount(frame, pendingBounds, windowManager) - return frameInfoHelper.info!! - } - return result - } - - fun updateDefaultFrameInfoOnProjectClose() { - val windowManager = WindowManager.getInstance() as WindowManagerImpl - if (frameInfoHelper.isDirty || frameInfoHelper.info == null) { - // not really required, because will be applied during project save on close - frameInfoHelper.updateAndGetModificationCount(project, pendingBounds, windowManager) - } - else { - updateDefaultFrameInfoInDeviceSpace(windowManager, frameInfoHelper.info ?: return) - } + internal fun getActualFrameInfoInDeviceSpace(frameHelper: ProjectFrameHelper, frame: JFrame, windowManager: WindowManagerImpl): FrameInfo { + return frameInfoHelper.updateAndGetInfo(frameHelper, frame, pendingBounds, windowManager) } fun markDirty(bounds: Rectangle?) { diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.kt index c07cc549a114..aff5d9815aec 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/ToolWindowManagerImpl.kt @@ -411,7 +411,7 @@ open class ToolWindowManagerImpl(val project: Project) : ToolWindowManagerEx(), if (toolWindowPane == null) { if (!ApplicationManager.getApplication().isUnitTestMode) { - LOG.warn("ProjectFrameAllocator is not used - use ProjectManager.openProject to open project in a correct way") + LOG.error("ProjectFrameAllocator is not used - use ProjectManager.openProject to open project in a correct way") } val toolWindowsPane = init((WindowManager.getInstance() as WindowManagerImpl).allocateFrame(project)) diff --git a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.kt b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.kt index b7695d14f167..b0f310ee9fe2 100644 --- a/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.kt +++ b/platform/platform-impl/src/com/intellij/openapi/wm/impl/WindowManagerImpl.kt @@ -93,7 +93,7 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific // Cannot mark as dirty and compute later, because to convert user space info to device space, // we need graphicsConfiguration, but we can get graphicsConfiguration only from frame, // but later, when getStateModificationCount or getState is called, may be no frame at all. - defaultFrameInfoHelper.updateFrameInfo(frameHelper) + defaultFrameInfoHelper.updateFrameInfo(frameHelper, frame) } else if (!project.isDisposed) { ProjectFrameBounds.getInstance(project).markDirty(if (isMaximized(extendedState)) null else bounds) @@ -302,6 +302,9 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific frame.addComponentListener(frameStateListener) } + /** + * This method is not used in a normal conditions. Only in case of violation and early access to ToolWindowManager. + */ fun allocateFrame(project: Project, projectFrameHelperFactory: Supplier = Supplier { ProjectFrameHelper(createNewProjectFrame(forceDisableAutoRequestFocus = false, frameInfo = null), null) @@ -323,15 +326,13 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific return frame } - private fun allocateNewFrame(project: Project, frame: ProjectFrameHelper) { - frame.init() + private fun allocateNewFrame(project: Project, frameHelper: ProjectFrameHelper) { + frameHelper.init() - var frameInfo = ProjectFrameBounds.getInstance(project).getFrameInfoInDeviceSpace() - if (frameInfo?.bounds == null) { - val lastFocusedProject = IdeFocusManager.getGlobalInstance().lastFocusedFrame?.project - if (lastFocusedProject != null) { - frameInfo = ProjectFrameBounds.getInstance(lastFocusedProject).getActualFrameInfoInDeviceSpace(frame, this) - } + var frameInfo: FrameInfo? = null + val lastFocusedProjectFrame = IdeFocusManager.getGlobalInstance().lastFocusedFrame?.project?.let { getFrameHelper(it) } + if (lastFocusedProjectFrame != null) { + frameInfo = getFrameInfoByFrameHelper(lastFocusedProjectFrame) if (frameInfo?.bounds == null) { frameInfo = defaultFrameInfoHelper.info } @@ -344,19 +345,19 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific } val bounds = frameInfo.bounds if (bounds != null) { - frame.frame!!.bounds = FrameBoundsConverter.convertFromDeviceSpaceAndFitToScreen(bounds) + frameHelper.frame!!.bounds = FrameBoundsConverter.convertFromDeviceSpaceAndFitToScreen(bounds) } } - frame.setProject(project) - projectToFrame.put(project, frame) - val uiFrame = frame.frame!! + frameHelper.setProject(project) + projectToFrame.put(project, frameHelper) + val uiFrame = frameHelper.frame!! if (frameInfo != null) { uiFrame.extendedState = frameInfo.extendedState } uiFrame.isVisible = true if (isFullScreenSupportedInCurrentOs() && frameInfo != null && frameInfo.fullScreen) { - frame.toggleFullScreen(true) + frameHelper.toggleFullScreen(true) } uiFrame.addComponentListener(frameStateListener) @@ -476,6 +477,12 @@ class WindowManagerImpl : WindowManagerEx(), PersistentStateComponentWithModific } override fun isFullScreenSupportedInCurrentOS() = isFullScreenSupportedInCurrentOs() + + override fun updateDefaultFrameInfoOnProjectClose(project: Project) { + val frameHelper = getFrameHelper(project) ?: return + val frameInfo = getFrameInfoByFrameHelper(frameHelper) ?: return + defaultFrameInfoHelper.copyFrom(frameInfo) + } } private fun calcAlphaModelSupported(): Boolean { @@ -544,4 +551,8 @@ private fun getIdeFrame(component: Component): IdeFrame? { is IdeFrame -> component else -> null } -} \ No newline at end of file +} + +private fun getFrameInfoByFrameHelper(frameHelper: ProjectFrameHelper): FrameInfo? { + return updateFrameInfo(frameHelper, frameHelper.frame ?: return null, null, null) +}