Skip to content

Commit 3f964ae

Browse files
committed
Fix macOS context menu always appearing in dark mode
- Add systemAppearance() helper to read system-wide theme from UserDefaults - Set NSMenu.appearance to match system theme instead of menu bar appearance - Update menu appearance when theme changes in MenuBarAppearanceObserver - Pass statusItem to nativeMenu() for consistency (future-proofing) The context menu now follows the global system theme (light/dark), independent of the menu bar appearance setting. Fixes issue where tray context menu remained in dark mode when system was in light mode.
1 parent 0704b92 commit 3f964ae

1 file changed

Lines changed: 19 additions & 3 deletions

File tree

maclib/tray.swift

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,11 @@ private class MenuBarAppearanceObserver {
113113
if let img = isDark ? ctx.darkImage : ctx.lightImage {
114114
ctx.statusItem.button?.image = img
115115
}
116+
117+
// Update menu appearance to match the system theme (not menu bar)
118+
if let menu = ctx.contextMenu {
119+
menu.appearance = systemAppearance()
120+
}
116121
}
117122

118123
// Cancel any pending settle callback before scheduling a new one.
@@ -138,11 +143,22 @@ private class MenuBarAppearanceObserver {
138143
private var menuDelegate: MenuDelegate?
139144

140145
// MARK: - Helpers
141-
private func nativeMenu(from menuPtr: UnsafeMutableRawPointer) -> NSMenu {
146+
147+
/// Returns the system-wide appearance (not the menu bar appearance)
148+
private func systemAppearance() -> NSAppearance {
149+
// Check if system is in dark mode via UserDefaults
150+
let isDarkMode = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark"
151+
let appearanceName: NSAppearance.Name = isDarkMode ? .darkAqua : .aqua
152+
return NSAppearance(named: appearanceName) ?? NSApp.effectiveAppearance
153+
}
154+
private func nativeMenu(from menuPtr: UnsafeMutableRawPointer, statusItem: NSStatusItem? = nil) -> NSMenu {
142155
let menu = NSMenu()
143156
menu.autoenablesItems = false
144157
menu.delegate = menuDelegate
145158

159+
// Set menu appearance to match the system theme (not menu bar)
160+
menu.appearance = systemAppearance()
161+
146162
var currentPtr = menuPtr
147163
while true {
148164
guard let textPtr = currentPtr.load(as: UnsafePointer<CChar>?.self) else { break }
@@ -179,7 +195,7 @@ private func nativeMenu(from menuPtr: UnsafeMutableRawPointer) -> NSMenu {
179195
menu.addItem(item)
180196

181197
if let submenuPtr = submenu {
182-
menu.setSubmenu(nativeMenu(from: submenuPtr), for: item)
198+
menu.setSubmenu(nativeMenu(from: submenuPtr, statusItem: statusItem), for: item)
183199
}
184200
}
185201

@@ -269,7 +285,7 @@ public func tray_update(_ tray: UnsafeMutableRawPointer) {
269285

270286
if let menuPtr = menuPtr {
271287
// Create and store the menu without assigning it to statusItem
272-
ctx.contextMenu = nativeMenu(from: menuPtr)
288+
ctx.contextMenu = nativeMenu(from: menuPtr, statusItem: statusItem)
273289
} else {
274290
ctx.contextMenu = nil
275291
}

0 commit comments

Comments
 (0)