From 2a51c82670d585a92d05ea9f04366327786c1977 Mon Sep 17 00:00:00 2001 From: CJ Barrett Date: Wed, 1 Mar 2023 10:14:59 -0500 Subject: [PATCH 1/2] Register for effectiveAppearance changes and notify the client. --- systray.go | 27 +++++++++++++++++---------- systray.h | 1 + systray_darwin.go | 5 +++++ systray_darwin.m | 15 +++++++++++++++ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/systray.go b/systray.go index 3d607a93..a93fca27 100644 --- a/systray.go +++ b/systray.go @@ -10,11 +10,12 @@ import ( ) var ( - systrayReady func() - systrayExit func() - systrayExitCalled bool - menuItems = make(map[uint32]*MenuItem) - menuItemsLock sync.RWMutex + systrayReady func() + systrayExit func() + systrayOnAppearanceChanged func(bool) + systrayExitCalled bool + menuItems = make(map[uint32]*MenuItem) + menuItemsLock sync.RWMutex currentID = uint32(0) quitOnce sync.Once @@ -78,17 +79,17 @@ func newMenuItem(title string, tooltip string, parent *MenuItem) *MenuItem { // Run initializes GUI and starts the event loop, then invokes the onReady // callback. It blocks until systray.Quit() is called. -func Run(onReady, onExit func()) { +func Run(onReady, onExit func(), onAppearanceChanged func(bool)) { setInternalLoop(true) - Register(onReady, onExit) + Register(onReady, onExit, onAppearanceChanged) nativeLoop() } // RunWithExternalLoop allows the systemtray module to operate with other tookits. // The returned start and end functions should be called by the toolkit when the application has started and will end. -func RunWithExternalLoop(onReady, onExit func()) (start, end func()) { - Register(onReady, onExit) +func RunWithExternalLoop(onReady, onExit func(), onAppearanceChanged func(bool)) (start, end func()) { + Register(onReady, onExit, onAppearanceChanged) return nativeStart, func() { nativeEnd() @@ -101,7 +102,7 @@ func RunWithExternalLoop(onReady, onExit func()) (start, end func()) { // needs to show other UI elements, for example, webview. // To overcome some OS weirdness, On macOS versions before Catalina, calling // this does exactly the same as Run(). -func Register(onReady func(), onExit func()) { +func Register(onReady func(), onExit func(), onAppearanceChanged func(bool)) { if onReady == nil { systrayReady = func() {} } else { @@ -266,3 +267,9 @@ func systrayMenuItemSelected(id uint32) { default: } } + +func systrayAppearanceChanged(dark bool) { + if systrayOnAppearanceChanged != nil { + systrayOnAppearanceChanged(dark) + } +} diff --git a/systray.h b/systray.h index 4858eb4d..0277afad 100644 --- a/systray.h +++ b/systray.h @@ -3,6 +3,7 @@ extern void systray_ready(); extern void systray_on_exit(); extern void systray_menu_item_selected(int menu_id); +extern void systray_appearance_changed(bool dark); void registerSystray(void); void nativeEnd(void); int nativeLoop(void); diff --git a/systray_darwin.go b/systray_darwin.go index 07907a84..9f72af11 100644 --- a/systray_darwin.go +++ b/systray_darwin.go @@ -151,3 +151,8 @@ func systray_on_exit() { func systray_menu_item_selected(cID C.int) { systrayMenuItemSelected(uint32(cID)) } + +//export systray_appearance_changed +func systray_appearance_changed(dark C.bool) { + systrayAppearanceChanged(bool(dark)) +} diff --git a/systray_darwin.m b/systray_darwin.m index f244ca5f..f01e3cc0 100644 --- a/systray_darwin.m +++ b/systray_darwin.m @@ -71,9 +71,24 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification self->menu = [[NSMenu alloc] init]; [self->menu setAutoenablesItems: FALSE]; [self->statusItem setMenu:self->menu]; + [self->statusItem addObserver:self forKeyPath:@"button.effectiveAppearance" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial context:nil]; systray_ready(); } +-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([keyPath isEqualToString:@"button.effectiveAppearance"]) { + NSStatusItem *item = object; + NSAppearance *appearance = item.button.effectiveAppearance; + NSString *appearanceName = (NSString*)(appearance.name); + if ([[appearanceName lowercaseString] containsString:@"dark"]) { + systray_appearance_changed(true); + } else { + systray_appearance_changed(false); + } + } +} + - (void)applicationWillTerminate:(NSNotification *)aNotification { systray_on_exit(); From 8a54b85729ffbacd2b1dda29a1260c54cf8e7bff Mon Sep 17 00:00:00 2001 From: CJ Barrett Date: Wed, 1 Mar 2023 10:23:37 -0500 Subject: [PATCH 2/2] Actually setting the callback func --- systray.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/systray.go b/systray.go index a93fca27..a7c2dc87 100644 --- a/systray.go +++ b/systray.go @@ -123,6 +123,12 @@ func Register(onReady func(), onExit func(), onAppearanceChanged func(bool)) { } systrayExit = onExit systrayExitCalled = false + + if onAppearanceChanged == nil { + onAppearanceChanged = func(bool) {} + } + systrayOnAppearanceChanged = onAppearanceChanged + registerSystray() } @@ -269,7 +275,5 @@ func systrayMenuItemSelected(id uint32) { } func systrayAppearanceChanged(dark bool) { - if systrayOnAppearanceChanged != nil { - systrayOnAppearanceChanged(dark) - } + systrayOnAppearanceChanged(dark) }