mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[settings] IJPL-249138 Non-modal settings: always open as pinned dialog when invoked from a macOS full-screen frame
When Settings were invoked from an IDE frame in macOS native full-screen (main frame or detached editor tab), they could spawn as a WindowFrame on a separate Space instead of a FloatDialog on the IDE's Space. Fix: force float/dialog mode when the invoking frame is in full-screen (isFloat || isInvokingFrameInFullScreen()), preserving the saved preference for non-full-screen sessions. MacFullScreenSupport now stores itself as a root-pane client property so full-screen state can be queried for FrameWrapper-based windows. The pin button and show() are updated accordingly. (cherry picked from commit 11a21abd23e64df2fb65e66624d6c482f55b77ea) IJ-CR-217470 GitOrigin-RevId: b307eef9307fe9d51322443a1a34e4a0318bea74
This commit is contained in:
committed by
intellij-monorepo-bot
parent
581faaae85
commit
9adcdf3bfc
@@ -25,6 +25,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.popup.util.PopupUtil
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.WindowStateService
|
||||
import com.intellij.openapi.wm.IdeFrame
|
||||
import com.intellij.openapi.wm.WindowManager
|
||||
import com.intellij.openapi.wm.impl.IdeFrameDecorator
|
||||
import com.intellij.openapi.wm.impl.IdeGlassPaneImpl
|
||||
@@ -51,6 +52,7 @@ import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import java.awt.EventQueue
|
||||
import java.awt.Frame
|
||||
import java.awt.KeyboardFocusManager
|
||||
import java.awt.Rectangle
|
||||
import java.awt.Toolkit
|
||||
import java.awt.Window
|
||||
@@ -123,6 +125,14 @@ abstract class NonModalWindowWrapper(
|
||||
/** Non-null only on macOS while [activeWindow] is a [WindowFrame]. Tracks native full-screen state. */
|
||||
private var fullScreenSupport: FullScreenSupport? = null
|
||||
|
||||
/**
|
||||
* The AWT window that had focus when this wrapper was constructed — i.e. the window the user
|
||||
* was in when they invoked the action that opened Settings. Captured eagerly so that
|
||||
* [isInvokingFrameInFullScreen] can identify the invoking IDE frame even after AWT focus
|
||||
* has shifted to the newly created Settings window.
|
||||
*/
|
||||
private val invokingWindow: Window? = KeyboardFocusManager.getCurrentKeyboardFocusManager().activeWindow
|
||||
|
||||
protected var isFloat: Boolean
|
||||
get() = PropertiesComponent.getInstance().getBoolean(floatModeKey, true)
|
||||
set(value) { PropertiesComponent.getInstance().setValue(floatModeKey, value, true) }
|
||||
@@ -196,7 +206,8 @@ abstract class NonModalWindowWrapper(
|
||||
IdeBundle.messagePointer("action.ToggleAction.description.pin.window"),
|
||||
AllIcons.General.Pin_tab,
|
||||
) {
|
||||
override fun isSelected(e: AnActionEvent): Boolean = isFloat
|
||||
override fun isSelected(e: AnActionEvent): Boolean =
|
||||
if (::activeWindow.isInitialized) activeWindow is FloatDialog else isFloat
|
||||
override fun setSelected(e: AnActionEvent, state: Boolean) {
|
||||
isFloat = state
|
||||
switchWindowMode(state)
|
||||
@@ -216,7 +227,11 @@ abstract class NonModalWindowWrapper(
|
||||
protected fun initWindow(content: JComponent, minSize: Dimension, initialSize: Dimension) {
|
||||
this.content = content
|
||||
this.minWindowSize = minSize
|
||||
activeWindow = createAwtWindow(isFloat, content, minSize, initialSize)
|
||||
// When the invoking IDE frame is in full-screen, always open as a dialog (float/pinned) so
|
||||
// the Settings window appears on the IDE's Space rather than spawning its own separate Space.
|
||||
// The saved preference is not modified so it is honoured the next time the IDE is not in full-screen.
|
||||
val effectiveFloat = isFloat || isInvokingFrameInFullScreen()
|
||||
activeWindow = createAwtWindow(effectiveFloat, content, minSize, initialSize)
|
||||
loadAndRegisterWindowState(activeWindow)
|
||||
fitWindowToScreen(activeWindow)
|
||||
installWindowListeners()
|
||||
@@ -599,6 +614,27 @@ abstract class NonModalWindowWrapper(
|
||||
protected fun getIdeJFrame(): JFrame? =
|
||||
ComponentUtil.getWindow(WindowManager.getInstance().getIdeFrame(project)?.component) as? JFrame
|
||||
|
||||
/**
|
||||
* Returns `true` if the window that triggered this invocation is in macOS native full-screen.
|
||||
*
|
||||
* Two mechanisms are used:
|
||||
* - [IdeFrame.isInFullScreen] — reliable for the main IDE JFrame (handled by the macOS frame decorator).
|
||||
* - [MacFullScreenSupport] stored as a root-pane client property — reliable for [FrameWrapper]-based
|
||||
* windows (e.g. detached editor tabs) whose [IdeFrame.isInFullScreen] always returns `false`.
|
||||
*
|
||||
* Returns `false` on non-macOS.
|
||||
*/
|
||||
private fun isInvokingFrameInFullScreen(): Boolean {
|
||||
val ultimateParent = ComponentUtil.findUltimateParent(invokingWindow ?: return false)
|
||||
// Main IDE frame: IdeFrame.isInFullScreen() is reliable (MacMainFrameDecorator).
|
||||
if ((ultimateParent as? IdeFrame)?.isInFullScreen == true) return true
|
||||
// Detached editor tabs (FrameWrapper.MyJFrame): isInFullScreen() always returns false,
|
||||
// so fall back to MacFullScreenSupport stored in the root pane by addListener.
|
||||
val rootPane = (invokingWindow as? RootPaneContainer)?.rootPane ?: return false
|
||||
val fss = rootPane.getClientProperty(MacFullScreenSupport.ROOT_PANE_KEY) as? MacFullScreenSupport
|
||||
return fss?.isFullScreen == true
|
||||
}
|
||||
|
||||
// ── Public API ───────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,8 +32,14 @@ public final class MacFullScreenSupport implements FullScreenSupport {
|
||||
return myIsFullScreen;
|
||||
}
|
||||
|
||||
/** Client-property key on the window's root pane; value is the {@link MacFullScreenSupport} for that window. */
|
||||
public static final String ROOT_PANE_KEY = "MacFullScreenSupport";
|
||||
|
||||
@Override
|
||||
public void addListener(@NotNull Window window) {
|
||||
if (window instanceof RootPaneContainer container && container.getRootPane() != null) {
|
||||
container.getRootPane().putClientProperty(ROOT_PANE_KEY, this);
|
||||
}
|
||||
myListener = new FullScreenListener() {
|
||||
@Override
|
||||
public void windowEnteringFullScreen(FullScreenEvent event) {
|
||||
@@ -82,6 +88,7 @@ public final class MacFullScreenSupport implements FullScreenSupport {
|
||||
public void removeListener(@NotNull Window window) {
|
||||
if (window instanceof RootPaneContainer container && container.getRootPane() != null) {
|
||||
FullScreenUtilities.removeFullScreenListenerFrom(window, myListener);
|
||||
container.getRootPane().putClientProperty(ROOT_PANE_KEY, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user