mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-19 14:00:29 +00:00
macOS: update AppIcon encoding
- make `ColorizedGhosttyIcon` codable - remove deprecated string encoding introduced in tip
This commit is contained in:
@@ -13,9 +13,9 @@ enum AppIcon: Equatable, Codable {
|
||||
case retro
|
||||
case xray
|
||||
/// Save full image data to avoid sandboxing issues
|
||||
case custom(fileData: Data)
|
||||
case customStyle(ghostColorHex: String, screenColorHexes: [String], iconFrame: Ghostty.MacOSIconFrame)
|
||||
|
||||
case custom(_ iconFile: Data)
|
||||
case customStyle(_ icon: ColorizedGhosttyIcon)
|
||||
|
||||
#if !DOCK_TILE_PLUGIN
|
||||
init?(config: Ghostty.Config) {
|
||||
switch config.macosIcon {
|
||||
@@ -39,7 +39,7 @@ enum AppIcon: Equatable, Codable {
|
||||
self = .xray
|
||||
case .custom:
|
||||
if let data = try? Data(contentsOf: URL(filePath: config.macosCustomIcon, relativeTo: nil)) {
|
||||
self = .custom(fileData: data)
|
||||
self = .custom(data)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
@@ -47,59 +47,16 @@ enum AppIcon: Equatable, Codable {
|
||||
// Discard saved icon name
|
||||
// if no valid colours were found
|
||||
guard
|
||||
let ghostColor = config.macosIconGhostColor?.hexString,
|
||||
let screenColors = config.macosIconScreenColor?.compactMap(\.hexString)
|
||||
let ghostColor = config.macosIconGhostColor,
|
||||
let screenColors = config.macosIconScreenColor
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
self = .customStyle(ghostColorHex: ghostColor, screenColorHexes: screenColors, iconFrame: config.macosIconFrame)
|
||||
self = .customStyle(ColorizedGhosttyIcon(screenColors: screenColors, ghostColor: ghostColor, frame: config.macosIconFrame))
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Restore the icon from previously saved values
|
||||
init?(string: String) {
|
||||
switch string {
|
||||
case Ghostty.MacOSIcon.official.rawValue:
|
||||
self = .official
|
||||
case Ghostty.MacOSIcon.blueprint.rawValue:
|
||||
self = .blueprint
|
||||
case Ghostty.MacOSIcon.chalkboard.rawValue:
|
||||
self = .chalkboard
|
||||
case Ghostty.MacOSIcon.glass.rawValue:
|
||||
self = .glass
|
||||
case Ghostty.MacOSIcon.holographic.rawValue:
|
||||
self = .holographic
|
||||
case Ghostty.MacOSIcon.microchip.rawValue:
|
||||
self = .microchip
|
||||
case Ghostty.MacOSIcon.paper.rawValue:
|
||||
self = .paper
|
||||
case Ghostty.MacOSIcon.retro.rawValue:
|
||||
self = .retro
|
||||
case Ghostty.MacOSIcon.xray.rawValue:
|
||||
self = .xray
|
||||
default:
|
||||
var parts = string.split(separator: "_").map(String.init)
|
||||
if
|
||||
let _ = parts.first.flatMap(NSColor.init(hex:)),
|
||||
let frame = parts.last.flatMap(Ghostty.MacOSIconFrame.init(rawValue:))
|
||||
{
|
||||
let ghostC = parts.removeFirst()
|
||||
_ = parts.removeLast()
|
||||
self = .customStyle(
|
||||
ghostColorHex: ghostC,
|
||||
screenColorHexes: parts,
|
||||
iconFrame: frame
|
||||
)
|
||||
} else {
|
||||
// Due to sandboxing with `com.apple.dock.external.extra.arm64`,
|
||||
// we can’t restore custom icon file automatically.
|
||||
// The user must open the app to update it.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func image(in bundle: Bundle) -> NSImage? {
|
||||
switch self {
|
||||
case .official:
|
||||
@@ -121,24 +78,9 @@ enum AppIcon: Equatable, Codable {
|
||||
case .xray:
|
||||
return bundle.image(forResource: "XrayImage")!
|
||||
case let .custom(file):
|
||||
if let userIcon = NSImage(data: file) {
|
||||
return userIcon
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case let .customStyle(ghostColorHex, screenColorHexes, macosIconFrame):
|
||||
let screenColors = screenColorHexes.compactMap(NSColor.init(hex:))
|
||||
guard
|
||||
let ghostColor = NSColor(hex: ghostColorHex),
|
||||
let icon = ColorizedGhosttyIcon(
|
||||
screenColors: screenColors,
|
||||
ghostColor: ghostColor,
|
||||
frame: macosIconFrame
|
||||
).makeImage(in: bundle)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
return icon
|
||||
return NSImage(data: file)
|
||||
case let .customStyle(customIcon):
|
||||
return customIcon.makeImage(in: bundle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,33 @@
|
||||
import Cocoa
|
||||
|
||||
struct ColorizedGhosttyIcon {
|
||||
struct ColorizedGhosttyIcon: Codable, Equatable {
|
||||
init(screenColors: [NSColor], ghostColor: NSColor, frame: Ghostty.MacOSIconFrame) {
|
||||
self.screenColors = screenColors
|
||||
self.ghostColor = ghostColor
|
||||
self.frame = frame
|
||||
}
|
||||
|
||||
init(from decoder: any Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let screenColorHexes = try container.decode([String].self, forKey: .screenColors)
|
||||
let screenColors = screenColorHexes.compactMap(NSColor.init(hex:))
|
||||
let ghostColorHex = try container.decode(String.self, forKey: .ghostColor)
|
||||
guard let ghostColor = NSColor(hex: ghostColorHex) else {
|
||||
throw NSError(domain: "Custom Icon Error", code: 1, userInfo: [
|
||||
NSLocalizedDescriptionKey: "Failed to decode ghost color from \(ghostColorHex)"
|
||||
])
|
||||
}
|
||||
let frame = try container.decode(Ghostty.MacOSIconFrame.self, forKey: .frame)
|
||||
self.init(screenColors: screenColors, ghostColor: ghostColor, frame: frame)
|
||||
}
|
||||
|
||||
func encode(to encoder: any Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(screenColors.compactMap(\.hexString), forKey: .screenColors)
|
||||
try container.encode(ghostColor.hexString, forKey: .ghostColor)
|
||||
try container.encode(frame, forKey: .frame)
|
||||
}
|
||||
|
||||
/// The colors that make up the gradient of the screen.
|
||||
let screenColors: [NSColor]
|
||||
|
||||
@@ -10,6 +37,12 @@ struct ColorizedGhosttyIcon {
|
||||
/// The frame type to use
|
||||
let frame: Ghostty.MacOSIconFrame
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case screenColors
|
||||
case ghostColor
|
||||
case frame
|
||||
}
|
||||
|
||||
/// Make a custom colorized ghostty icon.
|
||||
func makeImage(in bundle: Bundle) -> NSImage? {
|
||||
// All of our layers (not in order)
|
||||
|
||||
@@ -11,14 +11,6 @@ extension UserDefaults {
|
||||
removeObject(forKey: Self.customIconKeyOld)
|
||||
}
|
||||
|
||||
// If we have an old, pre-docktileplugin value, then we parse the
|
||||
// the old value (try) and set it.
|
||||
if let previous = string(forKey: Self.customIconKeyOld), let newIcon = AppIcon(string: previous) {
|
||||
// update new storage once
|
||||
self.appIcon = newIcon
|
||||
return newIcon
|
||||
}
|
||||
|
||||
// Check if we have the new key for our dock tile plugin format.
|
||||
guard let data = data(forKey: Self.customIconKeyNew) else {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user