Last active
January 2, 2024 04:18
-
-
Save kirb/5f7870b99c9ebf6c2201f9500cbdd766 to your computer and use it in GitHub Desktop.
Get Mac device image based on device class - https://kirb.me/2023/04/15/mac-device-icon-by-device-class.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Cocoa | |
import UniformTypeIdentifiers | |
extension UTTagClass { | |
static let deviceModelCode = UTTagClass(rawValue: "com.apple.device-model-code") | |
} | |
extension UTType { | |
static let macBook = UTType("com.apple.mac.laptop") | |
static let macBookWithNotch = UTType("com.apple.mac.notched-laptop") | |
static let macMini = UTType("com.apple.macmini") | |
static let macStudio = UTType("com.apple.macstudio") | |
static let iMac = UTType("com.apple.imac") | |
static let macPro = UTType("com.apple.macpro") | |
static let macPro2013 = UTType("com.apple.macpro-cylinder") | |
static let macPro2019 = UTType("com.apple.macpro-2019") | |
} | |
struct Device { | |
static let machine: String? = { | |
#if os(macOS) || targetEnvironment(macCatalyst) | |
let key = "hw.model" | |
#else | |
let key = "hw.machine" | |
#endif | |
var size = size_t() | |
sysctlbyname(key, nil, &size, nil, 0) | |
let value = malloc(size) | |
defer { | |
value?.deallocate() | |
} | |
sysctlbyname(key, value, &size, nil, 0) | |
guard let cChar = value?.bindMemory(to: CChar.self, capacity: size) else { | |
return nil | |
} | |
return String(cString: cChar) | |
}() | |
private static func conforms(to type: UTType?) -> Bool { | |
guard let type, | |
let machine else { | |
return false | |
} | |
return UTType(tag: machine, tagClass: .deviceModelCode, conformingTo: nil)? | |
.conforms(to: type) ?? false | |
} | |
static let symbolName: String = { | |
if conforms(to: .macBookWithNotch), | |
#available(macOS 14.0, *) { | |
// macbook.gen2 was added with SF Symbols 5.0 (macOS Sonoma, 2023), but MacBooks with a notch | |
// were released in 2021! | |
return "macbook.gen2" | |
} else if conforms(to: .macBook) { | |
return "laptopcomputer" | |
} else if conforms(to: .macMini) { | |
return "macmini" | |
} else if conforms(to: .macStudio) { | |
return "macstudio" | |
} else if conforms(to: .iMac) { | |
return "desktopcomputer" | |
} else if conforms(to: .macPro2019) { | |
return "macpro.gen3" | |
} else if conforms(to: .macPro2013) { | |
return "macpro.gen2" | |
} else if conforms(to: .macPro) { | |
return "macpro" | |
} | |
return "display" | |
}() | |
} |
@waydabber I experienced the same problem. The following changes to conforms(to:)
seem to work.
private static func conforms(to hardwareModelClass: UTType?) -> Bool {
guard let hardwareModelClass, let machine else {
return false
}
let hardwareModelUTType = UTType(tag: machine,
tagClass: .deviceModelCode,
conformingTo: nil)
return hardwareModelUTType.map {
$0.conforms(to: hardwareModelClass)
} ?? false
}
Also, this is great! Thanks for figuring this out, @kirb !
Thanks @jpavao! And sorry I didn’t get to looking at this sooner, @waydabber.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hmm. Thanks for the code! It might be me but conforms(to) always returns true as the UTType(tag: machine, tagClass: .deviceModelCode, conformingTo: type) is never seems to be nil. Because of this this code will always just return the first image in the list (namely "macbook.gen2").
(Trying with Sonoma beta4)