Files
netbird/client/ui/services/windowappearance_darwin.go
Brandon Hopkins ec0c36b0e7 [client] Add light mode with system, light, and dark theme options (#7344)
* desktop UI light mode

* Theme review fixes plus macOS window outline fix

* Windows runtime chrome re-theming plus apply serialization

* Windows chrome threading and theme event ordering fixes

* Darken toggle and setting sidebar text

* resolve theme appearance, apply on UI thread

* read theme once per window

* Re-assert Windows dark opt-in after SetTheme

* split app-wide GTK theming from per-window chrome

* Update Wails dependency and checksums

* KDE tray icon panel fix

* Five review fixes: theme ordering, cgo dedup, KDE panel resolution

* Path guard hardening, toggle contrast, windows comment

* non-vacuous escape tests

* Default view edits

* Polish settings nav, controls, borders, and disc

* Profiles settings boarder, modals, and buttons

* Additional edits based on feedback

* Switch colors away from slight blue hue

* Update missing lang

* Fix vertical tab active view
2026-09-11 08:25:10 -07:00

54 lines
1.6 KiB
Go

package services
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework AppKit
#import <AppKit/AppKit.h>
// forced < 0: follow the OS (appearance nil); 0: light; 1: dark.
//
// Assigns directly rather than dispatching: Theme.apply already runs this on
// the main thread. Deferring would outlive the caller's check that the window
// is alive, and the __bridge cast does not retain it, so the block could touch
// a freed NSWindow.
static void nbSetWindowAppearance(void *nsWindow, int forced) {
NSWindow *window = (__bridge NSWindow *)nsWindow;
if (forced < 0) {
window.appearance = nil;
} else {
NSAppearanceName name = forced == 1 ? NSAppearanceNameDarkAqua : NSAppearanceNameAqua;
window.appearance = [NSAppearance appearanceNamed:name];
}
}
*/
import "C"
import (
"unsafe"
"github.com/netbirdio/netbird/client/ui/preferences"
)
// setWindowAppearance pins the NSWindow appearance to the forced theme, or
// hands it back to the OS for ThemeSystem. Without this, a window created
// under one OS appearance keeps its dark/light frame after a manual theme
// flip, leaving a mismatched border around the webview. Must run on the main
// thread, which Theme.apply guarantees.
//
// The resolved appearance is unused: for ThemeSystem a nil NSAppearance lets
// AppKit track the OS itself, which cannot drift from a snapshot we took.
func setWindowAppearance(nsWindow unsafe.Pointer, pref preferences.Theme, _ bool) {
if nsWindow == nil {
return
}
forced := C.int(-1)
switch pref {
case preferences.ThemeLight:
forced = 0
case preferences.ThemeDark:
forced = 1
}
C.nbSetWindowAppearance(nsWindow, forced)
}