macos: manually show window to handle mission control behavior

Fixes #1018
Fixes #1020

This disables the "visibleAtLaunch" configuration in the xib and
manually shows the window when it loads. This lets us carefully control
what happens particularly when a window is full screen (native) and part
of Mission Control.

Previously, the behavior depended on the Settings.app "Prefer tabs
when opening documents" setting, but we didn't handle every behavior
correctly (see #1018 and #1020). I couldn't find a way to robustly
handle all cases because there are no published macOS APIs for
interacting with Mission Control...

Plus, terminals aren't really "documents" so it did confuse at least one
user that Ghostty would follow this configuration. We just incidently
did because we use native tabbing.

This PR takes full control into our own hands. Our behavior is now:

  - If a new window is created from a native fullscreen window, the
    new window is created into native fullscreen.

  - If a new tab is created from a native fullscreen window, the
    tab is added to the existing window and does not create a new space.

  - If a window or tab is created from a non-fullscreen window, the
    existing behaviors remain.
This commit is contained in:
Mitchell Hashimoto
2023-12-07 22:44:47 -08:00
parent 9b81d57cb9
commit 4b25356625
2 changed files with 20 additions and 6 deletions

View File

@ -13,7 +13,7 @@
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window title="👻 Ghostty" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="TerminalWindow" customModule="Ghostty" customModuleProvider="target">
<window title="👻 Ghostty" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="TerminalWindow" customModule="Ghostty" customModuleProvider="target">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="0.0" y="0.0" width="800" height="600"/>

View File

@ -63,16 +63,30 @@ class TerminalManager {
/// Create a new terminal window.
func newWindow(withBaseConfig base: Ghostty.SurfaceConfiguration? = nil) {
let c = createWindow(withBaseConfig: base)
if let window = c.window {
Self.lastCascadePoint = window.cascadeTopLeft(from: Self.lastCascadePoint)
let window = c.window!
// We want to go fullscreen if we're configured for new windows to go fullscreen
var toggleFullScreen = ghostty.windowFullscreen
// If the previous focused window prior to creating this window is fullscreen,
// then this window also becomes fullscreen.
if let parent = focusedSurface?.window, parent.styleMask.contains(.fullScreen) {
toggleFullScreen = true
}
if (ghostty.windowFullscreen) {
// NOTE: this doesn't properly handle non-native fullscreen yet
c.window?.toggleFullScreen(nil)
if (toggleFullScreen && !window.styleMask.contains(.fullScreen)) {
window.toggleFullScreen(nil)
}
c.showWindow(self)
// Only cascade if we aren't fullscreen. This has to be dispatched async
// because it takes one event loop tick for showWindow to work.
if (!window.styleMask.contains(.fullScreen)) {
DispatchQueue.main.async {
Self.lastCascadePoint = window.cascadeTopLeft(from: Self.lastCascadePoint)
}
}
}
/// Creates a new tab in the current main window. If there are no windows, a window