macos: change our minimum version to macOS 13

macOS 12 is officially EOL by Apple and the project only supports
officially supported versions of macOS. Once publicly released, users on
older macOS versions will have to use older released builds.
This commit is contained in:
Mitchell Hashimoto
2024-10-09 14:35:23 -07:00
parent 2f009b7262
commit eec77e271c
12 changed files with 24 additions and 126 deletions

View File

@ -48,7 +48,7 @@ beta users using Ghostty as their primary terminal. See more in
| Platform / Package | Links | Notes | | Platform / Package | Links | Notes |
| ------------------ | -------------------------------------------------------------------------- | -------------------------- | | ------------------ | -------------------------------------------------------------------------- | -------------------------- |
| macOS | [Tip ("Nightly")](https://github.com/ghostty-org/ghostty/releases/tag/tip) | MacOS 12+ Universal Binary | | macOS | [Tip ("Nightly")](https://github.com/ghostty-org/ghostty/releases/tag/tip) | MacOS 13+ Universal Binary |
| Linux | [Build from Source](#developing-ghostty) | | | Linux | [Build from Source](#developing-ghostty) | |
| Linux (NixOS/Nix) | [Use the Flake](#nix-package) | | | Linux (NixOS/Nix) | [Use the Flake](#nix-package) | |
| Linux (Arch) | [Use the AUR package](https://aur.archlinux.org/packages/ghostty-git) | | | Linux (Arch) | [Use the AUR package](https://aur.archlinux.org/packages/ghostty-git) | |

View File

@ -759,12 +759,10 @@ pub fn build(b: *std.Build) !void {
/// be used generally, it should only be used for Darwin-based OS currently. /// be used generally, it should only be used for Darwin-based OS currently.
fn osVersionMin(tag: std.Target.Os.Tag) ?std.Target.Query.OsVersion { fn osVersionMin(tag: std.Target.Os.Tag) ?std.Target.Query.OsVersion {
return switch (tag) { return switch (tag) {
// The lowest supported version of macOS is 12.x because // We support back to the earliest officially supported version
// this is the first version to support Apple Silicon so it is // of macOS by Apple. EOL versions are not supported.
// the earliest version we can virtualize to test (I only have
// an Apple Silicon machine for macOS).
.macos => .{ .semver = .{ .macos => .{ .semver = .{
.major = 12, .major = 13,
.minor = 0, .minor = 0,
.patch = 0, .patch = 0,
} }, } },

View File

@ -731,7 +731,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 0.1; MARKETING_VERSION = 0.1;
"OTHER_LDFLAGS[arch=*]" = "-lstdc++"; "OTHER_LDFLAGS[arch=*]" = "-lstdc++";
PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.ghostty; PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.ghostty;
@ -898,7 +898,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 0.1; MARKETING_VERSION = 0.1;
"OTHER_LDFLAGS[arch=*]" = "-lstdc++"; "OTHER_LDFLAGS[arch=*]" = "-lstdc++";
PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.ghostty.debug; PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.ghostty.debug;
@ -951,7 +951,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 12.0; MACOSX_DEPLOYMENT_TARGET = 13.0;
MARKETING_VERSION = 0.1; MARKETING_VERSION = 0.1;
"OTHER_LDFLAGS[arch=*]" = "-lstdc++"; "OTHER_LDFLAGS[arch=*]" = "-lstdc++";
PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.ghostty; PRODUCT_BUNDLE_IDENTIFIER = com.mitchellh.ghostty;

View File

@ -29,12 +29,7 @@ class TerminalToolbar: NSToolbar, NSToolbarDelegate {
super.init(identifier: identifier) super.init(identifier: identifier)
delegate = self delegate = self
centeredItemIdentifiers.insert(.titleText)
if #available(macOS 13.0, *) {
centeredItemIdentifiers.insert(.titleText)
} else {
centeredItemIdentifier = .titleText
}
} }
func toolbar(_ toolbar: NSToolbar, func toolbar(_ toolbar: NSToolbar,

View File

@ -447,19 +447,6 @@ extension Ghostty {
} }
window.makeFirstResponder(to) window.makeFirstResponder(to)
// On newer versions of macOS everything above works great so we're done.
if #available(macOS 13, *) { return }
// On macOS 12, splits do not properly gain focus. I don't know why, but
// it seems like the `focused` SwiftUI method doesn't work. We use
// NotificationCenter as a blunt force instrument to make it work.
if #available(macOS 12, *) {
NotificationCenter.default.post(
name: Notification.didBecomeFocusedSurface,
object: to
)
}
} }
} }
} }

View File

@ -230,10 +230,6 @@ extension Ghostty.Notification {
static let ghosttyToggleFullscreen = Notification.Name("com.mitchellh.ghostty.toggleFullscreen") static let ghosttyToggleFullscreen = Notification.Name("com.mitchellh.ghostty.toggleFullscreen")
static let FullscreenModeKey = ghosttyToggleFullscreen.rawValue static let FullscreenModeKey = ghosttyToggleFullscreen.rawValue
/// Notification that a surface is becoming focused. This is only sent on macOS 12 to
/// work around bugs. macOS 13+ should use the ".focused()" attribute.
static let didBecomeFocusedSurface = Notification.Name("com.mitchellh.ghostty.didBecomeFocusedSurface")
/// Notification sent to toggle split maximize/unmaximize. /// Notification sent to toggle split maximize/unmaximize.
static let didToggleSplitZoom = Notification.Name("com.mitchellh.ghostty.didToggleSplitZoom") static let didToggleSplitZoom = Notification.Name("com.mitchellh.ghostty.didToggleSplitZoom")

View File

@ -84,10 +84,6 @@ extension Ghostty {
// is up to date. See TerminalSurfaceView for why we don't use the NSView // is up to date. See TerminalSurfaceView for why we don't use the NSView
// resize callback. // resize callback.
GeometryReader { geo in GeometryReader { geo in
// We use these notifications to determine when the window our surface is
// attached to is or is not focused.
let pubBecomeFocused = center.publisher(for: Notification.didBecomeFocusedSurface, object: surfaceView)
#if canImport(AppKit) #if canImport(AppKit)
let pubBecomeKey = center.publisher(for: NSWindow.didBecomeKeyNotification) let pubBecomeKey = center.publisher(for: NSWindow.didBecomeKeyNotification)
let pubResign = center.publisher(for: NSWindow.didResignKeyNotification) let pubResign = center.publisher(for: NSWindow.didResignKeyNotification)
@ -130,45 +126,6 @@ extension Ghostty {
return true return true
} }
#endif #endif
.onReceive(pubBecomeFocused) { notification in
// We only want to run this on older macOS versions where the .focused
// method doesn't work properly. See the dispatch of this notification
// for more information.
if #available(macOS 13, *) { return }
DispatchQueue.main.async {
surfaceFocus = true
}
}
.onAppear() {
// Welcome to the SwiftUI bug house of horrors. On macOS 12 (at least
// 12.5.1, didn't test other versions), the order in which the view
// is added to the window hierarchy is such that $surfaceFocus is
// not set to true for the first surface in a window. As a result,
// new windows are key (they have window focus) but the terminal surface
// does not have surface until the user clicks. Bad!
//
// There is a very real chance that I am doing something wrong, but it
// works great as-is on macOS 13, so I've instead decided to make the
// older macOS hacky. A workaround is on initial appearance to "steal
// focus" under certain conditions that seem to imply we're in the
// screwy state.
if #available(macOS 13, *) {
// If we're on a more modern version of macOS, do nothing.
return
}
if #available(macOS 12, *) {
// On macOS 13, the view is attached to a window at this point,
// so this is one extra check that we're a new view and behaving odd.
guard surfaceView.window == nil else { return }
DispatchQueue.main.async {
surfaceFocus = true
}
}
// I don't know how older macOS versions behave but Ghostty only
// supports back to macOS 12 so its moot.
}
// If our geo size changed then we show the resize overlay as configured. // If our geo size changed then we show the resize overlay as configured.
if let surfaceSize = surfaceView.surfaceSize { if let surfaceSize = surfaceView.surfaceSize {
@ -338,7 +295,7 @@ extension Ghostty {
let overlay: Ghostty.Config.ResizeOverlay let overlay: Ghostty.Config.ResizeOverlay
let position: Ghostty.Config.ResizeOverlayPosition let position: Ghostty.Config.ResizeOverlayPosition
let duration: UInt let duration: UInt
let focusInstant: Any? let focusInstant: ContinuousClock.Instant?
// This is the last size that we processed. This is how we handle our // This is the last size that we processed. This is how we handle our
// timer state. // timer state.
@ -361,14 +318,12 @@ extension Ghostty {
// If we were focused recently we hide it as well. This avoids showing // If we were focused recently we hide it as well. This avoids showing
// the resize overlay when SwiftUI is lazily resizing. // the resize overlay when SwiftUI is lazily resizing.
if #available(macOS 13, iOS 16, *) { if let instant = focusInstant {
if let instant = focusInstant as? ContinuousClock.Instant { let d = instant.duration(to: ContinuousClock.now)
let d = instant.duration(to: ContinuousClock.now) if (d < .milliseconds(500)) {
if (d < .milliseconds(500)) { // Avoid this size completely.
// Avoid this size completely. lastSize = geoSize
lastSize = geoSize return true;
return true;
}
} }
} }

View File

@ -35,7 +35,7 @@ extension Ghostty {
// The time this surface last became focused. This is a ContinuousClock.Instant // The time this surface last became focused. This is a ContinuousClock.Instant
// on supported platforms. // on supported platforms.
@Published var focusInstant: Any? = nil @Published var focusInstant: ContinuousClock.Instant? = nil
// Returns sizing information for the surface. This is the raw C // Returns sizing information for the surface. This is the raw C
// structure because I'm lazy. // structure because I'm lazy.
@ -232,10 +232,8 @@ extension Ghostty {
} }
// On macOS 13+ we can store our continuous clock... // On macOS 13+ we can store our continuous clock...
if #available(macOS 13, iOS 16, *) { if (focused) {
if (focused) { focusInstant = ContinuousClock.now
focusInstant = ContinuousClock.now
}
} }
} }

View File

@ -30,7 +30,7 @@ extension Ghostty {
// The time this surface last became focused. This is a ContinuousClock.Instant // The time this surface last became focused. This is a ContinuousClock.Instant
// on supported platforms. // on supported platforms.
@Published var focusInstant: Any? = nil @Published var focusInstant: ContinuousClock.Instant? = nil
// Returns sizing information for the surface. This is the raw C // Returns sizing information for the surface. This is the raw C
// structure because I'm lazy. // structure because I'm lazy.
@ -73,10 +73,8 @@ extension Ghostty {
ghostty_surface_set_focus(surface, focused) ghostty_surface_set_focus(surface, focused)
// On macOS 13+ we can store our continuous clock... // On macOS 13+ we can store our continuous clock...
if #available(macOS 13, iOS 16, *) { if (focused) {
if (focused) { focusInstant = ContinuousClock.now
focusInstant = ContinuousClock.now
}
} }
} }

View File

@ -15,13 +15,7 @@ extension Scene {
} }
extension Backport where Content: Scene { extension Backport where Content: Scene {
func defaultSize(width: CGFloat, height: CGFloat) -> some Scene { // None currently
if #available(macOS 13, *) {
return content.defaultSize(width: width, height: height)
} else {
return content
}
}
} }
extension Backport where Content: View { extension Backport where Content: View {

View File

@ -29,11 +29,7 @@ extension NSScreen {
// We need to see if our visible frame height is less than the full // We need to see if our visible frame height is less than the full
// screen height minus the menu and notch and such. // screen height minus the menu and notch and such.
let menuHeight = NSApp.mainMenu?.menuBarHeight ?? 0 let menuHeight = NSApp.mainMenu?.menuBarHeight ?? 0
let notchInset: CGFloat = if #available(macOS 12, *) { let notchInset: CGFloat = safeAreaInsets.top
safeAreaInsets.top
} else {
0
}
let boundaryAreaPadding = 5.0 let boundaryAreaPadding = 5.0
return visibleFrame.height < (frame.height - max(menuHeight, notchInset) - boundaryAreaPadding) return visibleFrame.height < (frame.height - max(menuHeight, notchInset) - boundaryAreaPadding)

View File

@ -559,25 +559,15 @@ pub const Surface = struct {
// Clean up our core surface so that all the rendering and IO stop. // Clean up our core surface so that all the rendering and IO stop.
self.core_surface.deinit(); self.core_surface.deinit();
var tabgroup_opt: if (App.Darwin.enabled) ?objc.Object else void = undefined;
if (App.Darwin.enabled) { if (App.Darwin.enabled) {
const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(self.window).?); const nswindow = objc.Object.fromId(glfwNative.getCocoaWindow(self.window).?);
const tabgroup = nswindow.getProperty(objc.Object, "tabGroup"); const tabgroup = nswindow.getProperty(objc.Object, "tabGroup");
// On macOS versions prior to Ventura, we lose window focus on tab close
// for some reason. We manually fix this by keeping track of the tab
// group and just selecting the next window.
if (internal_os.macosVersionAtLeast(13, 0, 0))
tabgroup_opt = null
else
tabgroup_opt = tabgroup;
const windows = tabgroup.getProperty(objc.Object, "windows"); const windows = tabgroup.getProperty(objc.Object, "windows");
switch (windows.getProperty(usize, "count")) { switch (windows.getProperty(usize, "count")) {
// If we're going down to one window our tab bar is going to be // If we're going down to one window our tab bar is going to be
// destroyed so unset it so that the later logic doesn't try to // destroyed so unset it so that the later logic doesn't try to
// use it. // use it.
1 => tabgroup_opt = null, 1 => {},
// If our tab bar is visible and we are going down to 1 window, // If our tab bar is visible and we are going down to 1 window,
// hide the tab bar. The check is "2" because our current window // hide the tab bar. The check is "2" because our current window
@ -597,15 +587,6 @@ pub const Surface = struct {
c.destroy(); c.destroy();
self.cursor = null; self.cursor = null;
} }
// If we have a tabgroup set, we want to manually focus the next window.
// We should NOT have to do this usually, see the comments above.
if (App.Darwin.enabled) {
if (tabgroup_opt) |tabgroup| {
const selected = tabgroup.getProperty(objc.Object, "selectedWindow");
selected.msgSend(void, objc.sel("makeKeyWindow"), .{});
}
}
} }
/// Checks if the glfw window is in fullscreen. /// Checks if the glfw window is in fullscreen.