Skip to content

Commit 07275e8

Browse files
committed
Add dynamic system theme observer for context menu
- Add DistributedNotificationCenter observer for AppleInterfaceThemeChangedNotification - Track system theme separately from menu bar appearance - Update menu appearance immediately when system theme changes - Remove observer properly in invalidate() The context menu now updates dynamically when the user changes the system theme in System Preferences, without requiring app restart.
1 parent 3f964ae commit 07275e8

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

maclib/tray.swift

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ private class MenuBarAppearanceObserver {
7272
private var workItem: DispatchWorkItem?
7373
private var settleItem: DispatchWorkItem?
7474
private var lastAppearance: NSAppearance.Name?
75+
private var lastSystemTheme: Bool? // Track system theme separately
7576
private let trayPtr: UnsafeMutableRawPointer?
7677

7778
/// Debounce delay before first evaluation (keep tiny but non‑zero).
@@ -84,12 +85,41 @@ private class MenuBarAppearanceObserver {
8485
}
8586

8687
func startObserving(_ statusItem: NSStatusItem) {
88+
// Observe menu bar appearance changes
8789
observation = statusItem.button?.observe(
8890
\.effectiveAppearance,
8991
options: [.initial, .new]
9092
) { [weak self] button, _ in
9193
self?.scheduleCheck(for: button.effectiveAppearance)
9294
}
95+
96+
// Observe system-wide theme changes via DistributedNotificationCenter
97+
DistributedNotificationCenter.default().addObserver(
98+
forName: NSNotification.Name("AppleInterfaceThemeChangedNotification"),
99+
object: nil,
100+
queue: .main
101+
) { [weak self] _ in
102+
self?.handleSystemThemeChange()
103+
}
104+
105+
// Initial update of menu appearance
106+
handleSystemThemeChange()
107+
}
108+
109+
private func handleSystemThemeChange() {
110+
let isDark = UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark"
111+
112+
// Only update if theme actually changed
113+
if lastSystemTheme != isDark {
114+
lastSystemTheme = isDark
115+
116+
// Update menu appearance for all contexts
117+
if let ptr = trayPtr, let ctx = contexts[ptr] {
118+
if let menu = ctx.contextMenu {
119+
menu.appearance = systemAppearance()
120+
}
121+
}
122+
}
93123
}
94124

95125
private func scheduleCheck(for appearance: NSAppearance) {
@@ -136,6 +166,13 @@ private class MenuBarAppearanceObserver {
136166
observation = nil
137167
workItem?.cancel()
138168
settleItem?.cancel()
169+
170+
// Remove system theme observer
171+
DistributedNotificationCenter.default().removeObserver(
172+
self,
173+
name: NSNotification.Name("AppleInterfaceThemeChangedNotification"),
174+
object: nil
175+
)
139176
}
140177
}
141178

0 commit comments

Comments
 (0)