From 8437be8ee1e593afaff96f4d702cdce12e97cecd Mon Sep 17 00:00:00 2001 From: Lukas <134181853+bo2themax@users.noreply.github.com> Date: Tue, 11 Nov 2025 11:30:44 +0100 Subject: [PATCH 1/3] macOS: 'restore' non native fullscreen styles --- .../Features/Terminal/TerminalRestorable.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/macos/Sources/Features/Terminal/TerminalRestorable.swift b/macos/Sources/Features/Terminal/TerminalRestorable.swift index 1e640967e..56fa48d55 100644 --- a/macos/Sources/Features/Terminal/TerminalRestorable.swift +++ b/macos/Sources/Features/Terminal/TerminalRestorable.swift @@ -109,6 +109,17 @@ class TerminalWindowRestoration: NSObject, NSWindowRestoration { } completionHandler(window, nil) + // We don't restore the previous fullscreen mode. If the saved mode differs from + // the current configuration, using either could be confusing. Instead, we honor + // the configured mode (consistent with new_window behavior). + let mode = appDelegate.ghostty.config.windowFullscreenMode + guard mode != .native else { + // We let AppKit handle native fullscreen + return + } + // Give the window to AppKit first, then adjust its frame and style + // to minimise any visible frame changes. + c.toggleFullscreen(mode: mode) } /// This restores the focus state of the surfaceview within the given window. When restoring, From 2debeb0f13d5c4582f750a367685cf70ed12663b Mon Sep 17 00:00:00 2001 From: Lukas <134181853+bo2themax@users.noreply.github.com> Date: Tue, 11 Nov 2025 16:09:38 +0100 Subject: [PATCH 2/3] macOS: save effective fullscreen styles --- .../Terminal/BaseTerminalController.swift | 18 ++++++++++++++++++ .../Features/Terminal/TerminalRestorable.swift | 9 ++++----- macos/Sources/Helpers/Fullscreen.swift | 2 +- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index 552f864ee..1bfae1674 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -66,6 +66,24 @@ class BaseTerminalController: NSWindowController, /// Fullscreen state management. private(set) var fullscreenStyle: FullscreenStyle? + /// The current effective fullscreen mode. + /// This is non-nil only while the window is in fullscreen. + var effectiveFullscreenMode: FullscreenMode? { + guard let fullscreenStyle, fullscreenStyle.isFullscreen else { + return nil + } + + switch fullscreenStyle { + case is NativeFullscreen: return .native + case is NonNativeFullscreen: return .nonNative + case is NonNativeFullscreenPaddedNotch: return .nonNativePaddedNotch + case is NonNativeFullscreenVisibleMenu: return .nonNativeVisibleMenu + default: + assertionFailure("Missing case here") + return nil + } + } + /// Event monitor (see individual events for why) private var eventMonitor: Any? = nil diff --git a/macos/Sources/Features/Terminal/TerminalRestorable.swift b/macos/Sources/Features/Terminal/TerminalRestorable.swift index 56fa48d55..b4691f2ca 100644 --- a/macos/Sources/Features/Terminal/TerminalRestorable.swift +++ b/macos/Sources/Features/Terminal/TerminalRestorable.swift @@ -8,10 +8,12 @@ class TerminalRestorableState: Codable { let focusedSurface: String? let surfaceTree: SplitTree + let effectiveFullscreenMode: FullscreenMode? init(from controller: TerminalController) { self.focusedSurface = controller.focusedSurface?.id.uuidString self.surfaceTree = controller.surfaceTree + self.effectiveFullscreenMode = controller.effectiveFullscreenMode } init?(coder aDecoder: NSCoder) { @@ -28,6 +30,7 @@ class TerminalRestorableState: Codable { self.surfaceTree = v.value.surfaceTree self.focusedSurface = v.value.focusedSurface + self.effectiveFullscreenMode = v.value.effectiveFullscreenMode } func encode(with coder: NSCoder) { @@ -109,11 +112,7 @@ class TerminalWindowRestoration: NSObject, NSWindowRestoration { } completionHandler(window, nil) - // We don't restore the previous fullscreen mode. If the saved mode differs from - // the current configuration, using either could be confusing. Instead, we honor - // the configured mode (consistent with new_window behavior). - let mode = appDelegate.ghostty.config.windowFullscreenMode - guard mode != .native else { + guard let mode = state.effectiveFullscreenMode, mode != .native else { // We let AppKit handle native fullscreen return } diff --git a/macos/Sources/Helpers/Fullscreen.swift b/macos/Sources/Helpers/Fullscreen.swift index 6c70e8cf7..2ce9baea8 100644 --- a/macos/Sources/Helpers/Fullscreen.swift +++ b/macos/Sources/Helpers/Fullscreen.swift @@ -2,7 +2,7 @@ import Cocoa import GhosttyKit /// The fullscreen modes we support define how the fullscreen behaves. -enum FullscreenMode { +enum FullscreenMode: String, Codable { case native case nonNative case nonNativeVisibleMenu From eff361987876b21fd543c5239b412d44047f4389 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Tue, 11 Nov 2025 09:21:08 -0800 Subject: [PATCH 3/3] macos: Require fullScreenMode on fullscreenStyle --- .../Terminal/BaseTerminalController.swift | 18 ------------------ .../Features/Terminal/TerminalRestorable.swift | 2 +- macos/Sources/Helpers/Fullscreen.swift | 6 ++++++ 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/macos/Sources/Features/Terminal/BaseTerminalController.swift b/macos/Sources/Features/Terminal/BaseTerminalController.swift index 1bfae1674..552f864ee 100644 --- a/macos/Sources/Features/Terminal/BaseTerminalController.swift +++ b/macos/Sources/Features/Terminal/BaseTerminalController.swift @@ -66,24 +66,6 @@ class BaseTerminalController: NSWindowController, /// Fullscreen state management. private(set) var fullscreenStyle: FullscreenStyle? - /// The current effective fullscreen mode. - /// This is non-nil only while the window is in fullscreen. - var effectiveFullscreenMode: FullscreenMode? { - guard let fullscreenStyle, fullscreenStyle.isFullscreen else { - return nil - } - - switch fullscreenStyle { - case is NativeFullscreen: return .native - case is NonNativeFullscreen: return .nonNative - case is NonNativeFullscreenPaddedNotch: return .nonNativePaddedNotch - case is NonNativeFullscreenVisibleMenu: return .nonNativeVisibleMenu - default: - assertionFailure("Missing case here") - return nil - } - } - /// Event monitor (see individual events for why) private var eventMonitor: Any? = nil diff --git a/macos/Sources/Features/Terminal/TerminalRestorable.swift b/macos/Sources/Features/Terminal/TerminalRestorable.swift index b4691f2ca..71e54b612 100644 --- a/macos/Sources/Features/Terminal/TerminalRestorable.swift +++ b/macos/Sources/Features/Terminal/TerminalRestorable.swift @@ -13,7 +13,7 @@ class TerminalRestorableState: Codable { init(from controller: TerminalController) { self.focusedSurface = controller.focusedSurface?.id.uuidString self.surfaceTree = controller.surfaceTree - self.effectiveFullscreenMode = controller.effectiveFullscreenMode + self.effectiveFullscreenMode = controller.fullscreenStyle?.fullscreenMode } init?(coder aDecoder: NSCoder) { diff --git a/macos/Sources/Helpers/Fullscreen.swift b/macos/Sources/Helpers/Fullscreen.swift index 2ce9baea8..78c967661 100644 --- a/macos/Sources/Helpers/Fullscreen.swift +++ b/macos/Sources/Helpers/Fullscreen.swift @@ -31,6 +31,7 @@ enum FullscreenMode: String, Codable { /// Protocol that must be implemented by all fullscreen styles. protocol FullscreenStyle { var delegate: FullscreenDelegate? { get set } + var fullscreenMode: FullscreenMode { get } var isFullscreen: Bool { get } var supportsTabs: Bool { get } init?(_ window: NSWindow) @@ -87,6 +88,7 @@ class FullscreenBase { /// macOS native fullscreen. This is the typical behavior you get by pressing the green fullscreen /// button on regular titlebars. class NativeFullscreen: FullscreenBase, FullscreenStyle { + var fullscreenMode: FullscreenMode { .native } var isFullscreen: Bool { window.styleMask.contains(.fullScreen) } var supportsTabs: Bool { true } @@ -127,6 +129,8 @@ class NativeFullscreen: FullscreenBase, FullscreenStyle { } class NonNativeFullscreen: FullscreenBase, FullscreenStyle { + var fullscreenMode: FullscreenMode { .nonNative } + // Non-native fullscreen never supports tabs because tabs require // the "titled" style and we don't have it for non-native fullscreen. var supportsTabs: Bool { false } @@ -439,10 +443,12 @@ class NonNativeFullscreen: FullscreenBase, FullscreenStyle { } class NonNativeFullscreenVisibleMenu: NonNativeFullscreen { + override var fullscreenMode: FullscreenMode { .nonNativeVisibleMenu } override var properties: Properties { Properties(hideMenu: false) } } class NonNativeFullscreenPaddedNotch: NonNativeFullscreen { + override var fullscreenMode: FullscreenMode { .nonNativePaddedNotch } override var properties: Properties { Properties(paddedNotch: true) } }