diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj
index ab6dde118..fcd84e266 100644
--- a/macos/Ghostty.xcodeproj/project.pbxproj
+++ b/macos/Ghostty.xcodeproj/project.pbxproj
@@ -147,6 +147,7 @@
Features/Update/UpdatePopoverView.swift,
Features/Update/UpdateSimulator.swift,
Features/Update/UpdateViewModel.swift,
+ "Ghostty/Extensions/NSWorkspace+Ghostty.swift",
"Ghostty/FullscreenMode+Extension.swift",
Ghostty/Ghostty.Error.swift,
Ghostty/Ghostty.Event.swift,
diff --git a/macos/Sources/App/macOS/AppDelegate.swift b/macos/Sources/App/macOS/AppDelegate.swift
index 0db39a09e..c0f739a2d 100644
--- a/macos/Sources/App/macOS/AppDelegate.swift
+++ b/macos/Sources/App/macOS/AppDelegate.swift
@@ -65,6 +65,7 @@ class AppDelegate: NSObject,
@IBOutlet private var menuReturnToDefaultSize: NSMenuItem?
@IBOutlet private var menuFloatOnTop: NSMenuItem?
@IBOutlet private var menuUseAsDefault: NSMenuItem?
+ @IBOutlet private var menuSetAsDefaultTerminal: NSMenuItem?
@IBOutlet private var menuIncreaseFontSize: NSMenuItem?
@IBOutlet private var menuDecreaseFontSize: NSMenuItem?
@@ -577,6 +578,7 @@ class AppDelegate: NSObject,
self.menuChangeTabTitle?.setImageIfDesired(systemSymbolName: "pencil.line")
self.menuTerminalInspector?.setImageIfDesired(systemSymbolName: "scope")
self.menuReadonly?.setImageIfDesired(systemSymbolName: "eye.fill")
+ self.menuSetAsDefaultTerminal?.setImageIfDesired(systemSymbolName: "star.fill")
self.menuToggleFullScreen?.setImageIfDesired(systemSymbolName: "square.arrowtriangle.4.outward")
self.menuToggleVisibility?.setImageIfDesired(systemSymbolName: "eye")
self.menuZoomSplit?.setImageIfDesired(systemSymbolName: "arrow.up.left.and.arrow.down.right")
@@ -1292,6 +1294,21 @@ extension AppDelegate {
ud.removeObject(forKey: key)
}
}
+
+ @IBAction func setAsDefaultTerminal(_ sender: NSMenuItem) {
+ do {
+ try NSWorkspace.shared.setGhosttyAsDefaultTerminal()
+ // Success - menu state will automatically update via validateMenuItem
+ } catch {
+ // Show error dialog
+ let alert = NSAlert()
+ alert.messageText = "Failed to Set Default Terminal"
+ alert.informativeText = "Ghostty could not be set as the default terminal application.\n\nError: \(error.localizedDescription)"
+ alert.alertStyle = .warning
+ alert.addButton(withTitle: "OK")
+ alert.runModal()
+ }
+ }
}
// MARK: NSMenuItemValidation
@@ -1299,6 +1316,12 @@ extension AppDelegate {
extension AppDelegate: NSMenuItemValidation {
func validateMenuItem(_ item: NSMenuItem) -> Bool {
switch item.action {
+ case #selector(setAsDefaultTerminal(_:)):
+ // Check if Ghostty is already the default terminal
+ let isDefault = NSWorkspace.shared.isGhosttyDefaultTerminal
+ // Disable menu item if already default (option A)
+ return !isDefault
+
case #selector(floatOnTop(_:)),
#selector(useAsDefault(_:)):
// Float on top items only active if the key window is a primary
diff --git a/macos/Sources/App/macOS/MainMenu.xib b/macos/Sources/App/macOS/MainMenu.xib
index e28344098..28c2a09c4 100644
--- a/macos/Sources/App/macOS/MainMenu.xib
+++ b/macos/Sources/App/macOS/MainMenu.xib
@@ -60,6 +60,7 @@
+
@@ -109,6 +110,12 @@
+