summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitchell Hashimoto <m@mitchellh.com>2025-08-21 10:13:38 -0700
committerGitHub <noreply@github.com>2025-08-21 10:13:38 -0700
commitd20376c1ff7e9490e34499fa59c54bbdd68f4ebf (patch)
treea831a94498e6adc295601c2533726b4622f3c4c4
parent66e5081721e4e2158343a4b239b7ffc09dc8cbf2 (diff)
parentf178f4419e1815d514b267c7bc890a4f2c91e9ec (diff)
macOS Custom Icon + Persistence (#8230)
This PR aims to improve custom icons on macOS in the following ways. (I based this PR on the discussion #3631) ### Currently - Current Icon customizations are not persistent *(when closing the application the icon in dock reverts back to official icon)* - There is no officially supported way to change icon to be something completely custom. ### After this PR - Current icon customizations are persistent (closing the application no longer reverts back to official icon) - Ghostty config `macos-icon` has a new option `custom` which by default looks for icon `~/.config/ghostty/Ghostty.icns`. It has an accompanying new configuration `macos-custom-icon` which allows for a different path to be specified, it does support more than just `.icns` as well. Both changes are based on the thread with @sfsam in https://github.com/ghostty-org/ghostty/discussions/3631#discussioncomment-12180647 Feedback is always welcome, if I have not done something up to par please let me know and I will do my best to correct it. NOTE: I did notice some newlines with indents which seems to be against convention in those files so I removed the whitespace if this is not preferred I can revert. --- P.S. Thanks for all the work you put into making an awesome terminal!
-rw-r--r--macos/Sources/App/macOS/AppDelegate.swift14
-rw-r--r--macos/Sources/Ghostty/Ghostty.Config.swift20
-rw-r--r--macos/Sources/Ghostty/Package.swift1
-rw-r--r--src/config/Config.zig12
4 files changed, 44 insertions, 3 deletions
diff --git a/macos/Sources/App/macOS/AppDelegate.swift b/macos/Sources/App/macOS/AppDelegate.swift
index 5940547b5..cbd3668c5 100644
--- a/macos/Sources/App/macOS/AppDelegate.swift
+++ b/macos/Sources/App/macOS/AppDelegate.swift
@@ -119,6 +119,9 @@ class AppDelegate: NSObject,
@Published private(set) var appIcon: NSImage? = nil {
didSet {
NSApplication.shared.applicationIconImage = appIcon
+ let appPath = Bundle.main.bundlePath
+ NSWorkspace.shared.setIcon(appIcon, forFile: appPath, options: [])
+ NSWorkspace.shared.noteFileSystemChanged(appPath)
}
}
@@ -255,13 +258,13 @@ class AppDelegate: NSObject,
// Setup signal handlers
setupSignals()
-
+
// If we launched via zig run then we need to force foreground.
if Ghostty.launchSource == .zig_run {
// This never gets called until we click the dock icon. This forces it
// activate immediately.
applicationDidBecomeActive(.init(name: NSApplication.didBecomeActiveNotification))
-
+
// We run in the background, this forces us to the front.
DispatchQueue.main.async {
NSApp.setActivationPolicy(.regular)
@@ -834,6 +837,13 @@ class AppDelegate: NSObject,
case .xray:
self.appIcon = NSImage(named: "XrayImage")!
+ case .custom:
+ if let userIcon = NSImage(contentsOfFile: config.macosCustomIcon) {
+ self.appIcon = userIcon
+ } else {
+ self.appIcon = nil // Revert back to official icon if invalid location
+ }
+
case .customStyle:
guard let ghostColor = config.macosIconGhostColor else { break }
guard let screenColors = config.macosIconScreenColor else { break }
diff --git a/macos/Sources/Ghostty/Ghostty.Config.swift b/macos/Sources/Ghostty/Ghostty.Config.swift
index 241c10632..a223b2a0a 100644
--- a/macos/Sources/Ghostty/Ghostty.Config.swift
+++ b/macos/Sources/Ghostty/Ghostty.Config.swift
@@ -164,7 +164,7 @@ extension Ghostty {
let key = "window-position-x"
return ghostty_config_get(config, &v, key, UInt(key.count)) ? v : nil
}
-
+
var windowPositionY: Int16? {
guard let config = self.config else { return nil }
var v: Int16 = 0
@@ -301,6 +301,24 @@ extension Ghostty {
return MacOSIcon(rawValue: str) ?? defaultValue
}
+ var macosCustomIcon: String {
+ #if os(macOS)
+ let homeDirURL = FileManager.default.homeDirectoryForCurrentUser
+ let ghosttyConfigIconPath = homeDirURL.appendingPathComponent(
+ ".config/ghostty/Ghostty.icns",
+ conformingTo: .fileURL).path()
+ let defaultValue = ghosttyConfigIconPath
+ guard let config = self.config else { return defaultValue }
+ var v: UnsafePointer<Int8>? = nil
+ let key = "macos-custom-icon"
+ guard ghostty_config_get(config, &v, key, UInt(key.count)) else { return defaultValue }
+ guard let ptr = v else { return defaultValue }
+ return String(cString: ptr)
+ #else
+ return ""
+ #endif
+ }
+
var macosIconFrame: MacOSIconFrame {
let defaultValue = MacOSIconFrame.aluminum
guard let config = self.config else { return defaultValue }
diff --git a/macos/Sources/Ghostty/Package.swift b/macos/Sources/Ghostty/Package.swift
index 9b05934df..73487f1bd 100644
--- a/macos/Sources/Ghostty/Package.swift
+++ b/macos/Sources/Ghostty/Package.swift
@@ -280,6 +280,7 @@ extension Ghostty {
case paper
case retro
case xray
+ case custom
case customStyle = "custom-style"
}
diff --git a/src/config/Config.zig b/src/config/Config.zig
index 5ac2d6617..178b9f851 100644
--- a/src/config/Config.zig
+++ b/src/config/Config.zig
@@ -2735,6 +2735,8 @@ keybind: Keybinds = .{},
/// * `blueprint`, `chalkboard`, `microchip`, `glass`, `holographic`,
/// `paper`, `retro`, `xray` - Official variants of the Ghostty icon
/// hand-created by artists (no AI).
+/// * `custom` - Use a completely custom icon. The location must be specified
+/// using the additional `macos-custom-icon` configuration
/// * `custom-style` - Use the official Ghostty icon but with custom
/// styles applied to various layers. The custom styles must be
/// specified using the additional `macos-icon`-prefixed configurations.
@@ -2753,6 +2755,15 @@ keybind: Keybinds = .{},
/// effort.
@"macos-icon": MacAppIcon = .official,
+/// The absolute path to the custom icon file.
+/// Supported formats include PNG, JPEG, and ICNS.
+///
+/// Defaults to `~/.config/ghostty/Ghostty.icns`
+///
+/// Note: This configuration is required when `macos-icon` is set to
+/// `custom`
+@"macos-custom-icon": ?[]const u8 = null,
+
/// The material to use for the frame of the macOS app icon.
///
/// Valid values:
@@ -6975,6 +6986,7 @@ pub const MacAppIcon = enum {
paper,
retro,
xray,
+ custom,
@"custom-style",
};