diff --git a/macos/Ghostty.xcodeproj/project.pbxproj b/macos/Ghostty.xcodeproj/project.pbxproj index 1e2e3f612..87033b409 100644 --- a/macos/Ghostty.xcodeproj/project.pbxproj +++ b/macos/Ghostty.xcodeproj/project.pbxproj @@ -10,6 +10,9 @@ 8503D7C72A549C66006CFF3D /* FullScreenHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */; }; 857F63812A5E64F200CA4815 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 857F63802A5E64F200CA4815 /* MainMenu.xib */; }; A51B78472AF4B58B00F3EDB9 /* TerminalWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51B78462AF4B58B00F3EDB9 /* TerminalWindow.swift */; }; + A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */ = {isa = PBXBuildFile; fileRef = A51BFC1D2B2FB5CE00E92F16 /* About.xib */; }; + A51BFC202B2FB64F00E92F16 /* AboutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */; }; + A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A51BFC212B2FB6B400E92F16 /* AboutView.swift */; }; A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */; }; A53426352A7DA53D00EBB7A2 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */; }; A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A535B9D9299C569B0017E2E4 /* ErrorView.swift */; }; @@ -51,6 +54,9 @@ 8503D7C62A549C66006CFF3D /* FullScreenHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenHandler.swift; sourceTree = ""; }; 857F63802A5E64F200CA4815 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; }; A51B78462AF4B58B00F3EDB9 /* TerminalWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TerminalWindow.swift; sourceTree = ""; }; + A51BFC1D2B2FB5CE00E92F16 /* About.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = About.xib; sourceTree = ""; }; + A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutController.swift; sourceTree = ""; }; + A51BFC212B2FB6B400E92F16 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; A5278A9A2AA05B2600CD3039 /* Ghostty.Input.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Ghostty.Input.swift; sourceTree = ""; }; A53426342A7DA53D00EBB7A2 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; A535B9D9299C569B0017E2E4 /* ErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorView.swift; sourceTree = ""; }; @@ -104,6 +110,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + A51BFC1C2B2FB5AB00E92F16 /* About */ = { + isa = PBXGroup; + children = ( + A51BFC1D2B2FB5CE00E92F16 /* About.xib */, + A51BFC1F2B2FB64F00E92F16 /* AboutController.swift */, + A51BFC212B2FB6B400E92F16 /* AboutView.swift */, + ); + path = About; + sourceTree = ""; + }; A53426362A7DC53000EBB7A2 /* Features */ = { isa = PBXGroup; children = ( @@ -111,6 +127,7 @@ A59630982AEE1C4400D64628 /* Terminal */, A5E112912AF73E4D00C6E0C2 /* ClipboardConfirmation */, A534263E2A7DCC5800EBB7A2 /* Settings */, + A51BFC1C2B2FB5AB00E92F16 /* About */, ); path = Features; sourceTree = ""; @@ -305,6 +322,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + A51BFC1E2B2FB5CE00E92F16 /* About.xib in Resources */, A5CB04382B0F1C1C009ED217 /* themes in Resources */, A545D1A22A5772CE006E0AE4 /* shell-integration in Resources */, A596309A2AEE1C6400D64628 /* Terminal.xib in Resources */, @@ -327,6 +345,7 @@ A59FB5CF2AE0DB50009128F3 /* InspectorView.swift in Sources */, A596309C2AEE1C9E00D64628 /* TerminalController.swift in Sources */, A56D58892ACDE6CA00508D2C /* ServiceProvider.swift in Sources */, + A51BFC222B2FB6B400E92F16 /* AboutView.swift in Sources */, A5278A9B2AA05B2600CD3039 /* Ghostty.Input.swift in Sources */, A59630972AEE163600D64628 /* HostingWindow.swift in Sources */, A59630A02AEF6AEB00D64628 /* TerminalManager.swift in Sources */, @@ -345,6 +364,7 @@ A59FB5D12AE0DEA7009128F3 /* MetalView.swift in Sources */, A55685E029A03A9F004303CE /* AppError.swift in Sources */, A535B9DA299C569B0017E2E4 /* ErrorView.swift in Sources */, + A51BFC202B2FB64F00E92F16 /* AboutController.swift in Sources */, A5CEAFFF29C2410700646FDA /* Backport.swift in Sources */, A5E112952AF73E8A00C6E0C2 /* ClipboardConfirmationController.swift in Sources */, 8503D7C72A549C66006CFF3D /* FullScreenHandler.swift in Sources */, diff --git a/macos/Sources/AppDelegate.swift b/macos/Sources/AppDelegate.swift index b99d45ba8..4b0398767 100644 --- a/macos/Sources/AppDelegate.swift +++ b/macos/Sources/AppDelegate.swift @@ -360,6 +360,10 @@ class AppDelegate: NSObject, ObservableObject, NSApplicationDelegate, UNUserNoti NSApp.activate(ignoringOtherApps: true) } + @IBAction func showAbout(_ sender: Any?) { + AboutController.shared.show() + } + @IBAction func showHelp(_ sender: Any) { guard let url = URL(string: "https://github.com/mitchellh/ghostty") else { return } NSWorkspace.shared.open(url) diff --git a/macos/Sources/Features/About/About.xib b/macos/Sources/Features/About/About.xib new file mode 100644 index 000000000..fe339493a --- /dev/null +++ b/macos/Sources/Features/About/About.xib @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macos/Sources/Features/About/AboutController.swift b/macos/Sources/Features/About/AboutController.swift new file mode 100644 index 000000000..2c6882eea --- /dev/null +++ b/macos/Sources/Features/About/AboutController.swift @@ -0,0 +1,37 @@ +import Foundation +import Cocoa +import SwiftUI + +class AboutController: NSWindowController, NSWindowDelegate { + static let shared: AboutController = AboutController() + + override var windowNibName: NSNib.Name? { "About" } + + override func windowDidLoad() { + guard let window = window else { return } + window.center() + window.contentView = NSHostingView(rootView: AboutView()) + } + + // MARK: - Functions + + func show() { + guard let window = window else { return } + window.makeKeyAndOrderFront(nil) + } + + //MARK: - First Responder + + @IBAction func close(_ sender: Any) { + self.window?.performClose(sender) + } + + @IBAction func closeWindow(_ sender: Any) { + self.window?.performClose(sender) + } + + // This is called when "escape" is pressed. + @objc func cancel(_ sender: Any?) { + close() + } +} diff --git a/macos/Sources/Features/About/AboutView.swift b/macos/Sources/Features/About/AboutView.swift new file mode 100644 index 000000000..7232f3ba0 --- /dev/null +++ b/macos/Sources/Features/About/AboutView.swift @@ -0,0 +1,30 @@ +import SwiftUI + +struct AboutView: View { + /// Read the commit from the bundle. + var commit: String { + guard let valueAny = Bundle.main.infoDictionary?["CFBundleVersion"], + let version = valueAny as? String else { + return "unknown" + } + + return version + } + + var body: some View { + VStack(alignment: .center) { + Image("AppIconImage") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(maxHeight: 96) + + Text("Ghostty") + .font(.title3) + + Text("Commit: \(commit)") + .font(.body) + } + .frame(minWidth: 300) + .padding() + } +} diff --git a/macos/Sources/Features/Terminal/Terminal.xib b/macos/Sources/Features/Terminal/Terminal.xib index a086ffe89..4078fa2c6 100644 --- a/macos/Sources/Features/Terminal/Terminal.xib +++ b/macos/Sources/Features/Terminal/Terminal.xib @@ -1,8 +1,8 @@ - + - + diff --git a/macos/Sources/MainMenu.xib b/macos/Sources/MainMenu.xib index c9317efbb..69ee9fe38 100644 --- a/macos/Sources/MainMenu.xib +++ b/macos/Sources/MainMenu.xib @@ -1,8 +1,8 @@ - + - + @@ -53,7 +53,7 @@ - +