A version of the NSMenuItem swizzling to hide menu icons that properly handles palette menus (which have icons and no text))
NSMenuItem+IconHiding.swift
edited
1extension NSMenuItem {
2 /// Disables all icons in all regular menu items.
3 ///
4 /// Call `NSMenuItem.disableIcons` early (from AppDelegate.init is good).
5 public static func disableIcons() {
6 let originalSelector = #selector(getter: image)
7 let nilImageSelector = #selector(returnNilInsteadOfImage)
8
9 guard
10 let originalMethod = class_getInstanceMethod(NSMenuItem.self, originalSelector),
11 let newMethod = class_getInstanceMethod(NSMenuItem.self, nilImageSelector)
12 else {
13 return
14 }
15
16 method_exchangeImplementations(originalMethod, newMethod)
17 }
18
19 @objc private func returnNilInsteadOfImage() -> NSImage? {
20 // In a palette menu, as appears for example in the "zoom" button of a window,
21 // we want the icons to appear because labels are hidden.
22 if let menu, case .palette = menu.presentationStyle {
23 // Because the method implementations are swapped, this will return the original image.
24 return self.returnNilInsteadOfImage()
25 } else {
26 return nil
27 }
28 }
29}