mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
Merge pull request #2429 from ghostty-org/push-svonxsqwnumx
macos: change our minimum version to macOS 13
This commit is contained in:
@ -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) | |
|
||||||
|
@ -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,
|
||||||
} },
|
} },
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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")
|
||||||
|
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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.
|
||||||
|
Reference in New Issue
Block a user