Skip to content

Instantly share code, notes, and snippets.

@kirb
Last active January 2, 2024 04:18
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kirb/5f7870b99c9ebf6c2201f9500cbdd766 to your computer and use it in GitHub Desktop.
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
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
Copy link

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)

@jpavao
Copy link

jpavao commented Jan 2, 2024

@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
    }

@jpavao
Copy link

jpavao commented Jan 2, 2024

Also, this is great! Thanks for figuring this out, @kirb !

@kirb
Copy link
Author

kirb commented Jan 2, 2024

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