Fix macOS quick terminal fullscreen in front of fullscreen window

When a main Ghostty window is in fullscreen mode, quick terminal could get
stuck after the first fullscreen toggle due to presentation options conflicts.
This fix improves handling of menu bar visibility when toggling fullscreen
on spaces that already have fullscreen windows.
This commit is contained in:
Bryan Lee
2025-04-14 22:49:15 +08:00
parent a9a601f884
commit c7ab9954ff
2 changed files with 31 additions and 16 deletions

View File

@ -33,9 +33,6 @@ class QuickTerminalController: BaseTerminalController {
/// The configuration derived from the Ghostty config so we don't need to rely on references.
private var derivedConfig: DerivedConfig
/// Storage for the window frame before entering fullscreen mode
private var savedWindowFrame: NSRect? = nil
init(_ ghostty: Ghostty.App,
position: QuickTerminalPosition = .top,
baseConfig base: Ghostty.SurfaceConfiguration? = nil,
@ -488,16 +485,9 @@ class QuickTerminalController: BaseTerminalController {
@objc private func onToggleFullscreen(notification: SwiftUI.Notification) {
guard let target = notification.object as? Ghostty.SurfaceView else { return }
guard target == self.focusedSurface else { return }
guard let window = self.window else { return }
guard let screen = window.screen ?? NSScreen.main else { return }
if let originalFrame = savedWindowFrame {
window.setFrame(originalFrame, display: true)
savedWindowFrame = nil
} else {
savedWindowFrame = window.frame
window.setFrame(screen.frame, display: true)
}
// We ignore the requested mode and always use non-native for the quick terminal
toggleFullscreen(mode: .nonNative)
}
@objc private func ghosttyConfigDidChange(_ notification: Notification) {

View File

@ -167,6 +167,9 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
// screen the window is currently on.
guard let screen = window.screen else { return }
// Check if we're on a space that has a fullscreen window already
let alreadyHasFullscreenWindow = hasScreenWithFullscreenWindow(screen)
// Save the state that we need to exit again
guard let savedState = SavedState(window) else { return }
self.savedState = savedState
@ -179,8 +182,9 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
hideDock()
}
// Hide the menu if requested
if (properties.hideMenu) {
// Hide the menu if requested and if we don't already have a fullscreen window
// on this space (which would cause conflicts with presentation options)
if (properties.hideMenu && !alreadyHasFullscreenWindow) {
hideMenu()
}
@ -325,11 +329,32 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle {
// MARK: Menu
func hideMenu() {
NSApp.acquirePresentationOption(.autoHideMenuBar)
// Check if we're on a space that already has a fullscreen window
// which would cause macOS to already have the menu bar hidden
let currentOptions = NSApp.presentationOptions
if !currentOptions.contains(.autoHideMenuBar) && !currentOptions.contains(.hideMenuBar) {
// Only set if not already managed by the system
NSApp.acquirePresentationOption(.autoHideMenuBar)
}
}
func unhideMenu() {
NSApp.releasePresentationOption(.autoHideMenuBar)
let currentOptions = NSApp.presentationOptions
if currentOptions.contains(.autoHideMenuBar) {
// Only release what we've acquired
NSApp.releasePresentationOption(.autoHideMenuBar)
}
}
/// Determines if a screen already has a fullscreen window, which would
/// affect how we handle presentation options
private func hasScreenWithFullscreenWindow(_ screen: NSScreen) -> Bool {
// Check if we're on a space with a fullscreen window already
let currentOptions = NSApp.presentationOptions
// If any of these are set, macOS is probably already managing the menu bar
return currentOptions.contains(.hideMenuBar) ||
currentOptions.contains(.autoHideMenuBar)
}
/// The state that must be saved for non-native fullscreen to exit fullscreen.