//go:build !android && !ios && !freebsd && !js package main import ( "runtime" "strings" log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/client/ui/services" ) func (t *Tray) applyIcon() { t.statusMu.Lock() connected := t.connected statusLabel := t.lastStatus t.statusMu.Unlock() hasUpdate := false if t.updater != nil { hasUpdate = t.updater.hasUpdate() } log.Infof("tray applyIcon: connected=%v hasUpdate=%v status=%q goos=%s", connected, hasUpdate, statusLabel, runtime.GOOS) icon, dark := t.iconForState() if runtime.GOOS == "darwin" { t.tray.SetTemplateIcon(icon) return } if runtime.GOOS == "linux" { // Wails' Linux SNI backend ignores SetDarkModeIcon (its // setDarkModeIcon just calls setIcon, last-write-wins), so we pick // the black-vs-white silhouette ourselves in iconForState based on // the panel theme and push a single SetIcon. Calling // SetDarkModeIcon here would only clobber that choice. t.tray.SetIcon(icon) return } t.tray.SetIcon(icon) if dark != nil { t.tray.SetDarkModeIcon(dark) } } // panelIsDark reports whether the desktop panel uses a dark colour scheme, so // the Linux branch of iconForState can choose the white silhouette. Defaults // to true when no detector is wired (panelDark nil — non-Linux, or the // freedesktop portal was unavailable), matching the common dark Linux panel. func (t *Tray) panelIsDark() bool { if t.panelDark == nil { return true } return t.panelDark() } func (t *Tray) iconForState() (icon, dark []byte) { t.statusMu.Lock() connected := t.connected statusLabel := t.lastStatus t.statusMu.Unlock() hasUpdate := false if t.updater != nil { hasUpdate = t.updater.hasUpdate() } connecting := strings.EqualFold(statusLabel, services.StatusConnecting) errored := strings.EqualFold(statusLabel, statusError) || strings.EqualFold(statusLabel, services.StatusDaemonUnavailable) needsLogin := strings.EqualFold(statusLabel, services.StatusNeedsLogin) || strings.EqualFold(statusLabel, services.StatusSessionExpired) || strings.EqualFold(statusLabel, services.StatusLoginFailed) if runtime.GOOS == "darwin" { switch { case connecting: return iconConnectingMacOS, nil case errored: return iconErrorMacOS, nil case needsLogin: return iconNeedsLoginMacOS, nil case connected && hasUpdate: return iconUpdateConnectedMacOS, nil case connected: return iconConnectedMacOS, nil case hasUpdate: return iconUpdateDisconnectedMacOS, nil default: return iconDisconnectedMacOS, nil } } if runtime.GOOS == "linux" { // Linux: monochrome silhouette chosen by panel theme. Wails' SNI // backend can't switch icons per theme itself (see applyIcon), so we // resolve black (light panel) vs white (dark panel) here and the // caller pushes a single SetIcon. The second return is unused on // Linux. dark := t.panelIsDark() pick := func(black, white []byte) ([]byte, []byte) { if dark { return white, nil } return black, nil } switch { case connecting: return pick(iconConnectingMono, iconConnectingMonoDark) case errored: return pick(iconErrorMono, iconErrorMonoDark) case needsLogin: return pick(iconNeedsLoginMono, iconNeedsLoginMonoDark) case connected && hasUpdate: return pick(iconUpdateConnectedMono, iconUpdateConnectedMonoDark) case connected: return pick(iconConnectedMono, iconConnectedMonoDark) case hasUpdate: return pick(iconUpdateDisconnectedMono, iconUpdateDisconnectedMonoDark) default: return pick(iconDisconnectedMono, iconDisconnectedMonoDark) } } // Windows: colored PNGs. switch { case connecting: return iconConnecting, nil case errored: return iconError, nil case needsLogin: return iconNeedsLogin, nil case connected && hasUpdate: return iconUpdateConnected, nil case connected: return iconConnected, iconConnectedDark case hasUpdate: return iconUpdateDisconnected, nil default: return iconDisconnected, nil } }