fix: always persist menubar icon removal from dragging (#5654)

This commit is contained in:
lwouis committed 2026-05-28 13:56:49 +02:00
1 parent d483c5aa88
commit a354fdecc8
2 files changed
+19 -17

No files matched your search

+15
View File
@@ -8,6 +8,7 @@ class Menubar {
private static var supportProjectMenuItem: NSMenuItem!
private static var myAccountMenuItem: NSMenuItem!
private static let menuDelegate = MenubarMenuDelegate()
private static var isVisibleObserver: NSKeyValueObservation?
@discardableResult
static func addMenuItem(_ title: String, _ action: Selector, _ keyEquivalent: String, _ symbolName: String?, _ color: NSColor? = nil, _ target: AnyObject? = nil) -> NSMenuItem {
@@ -55,6 +56,7 @@ class Menubar {
// the WindowServer has already laid the menubar out at its imageless default size, then
// invalidates NSStatusBarContentView mid-FBS-scene-update — `_NSDetectedLayoutRecursion`.
applyMenubarIconPreferences()
observeRemovalFromMenubar()
#if DEBUG
installQAMenuMiddleClickMonitor()
#endif
@@ -152,6 +154,19 @@ class Menubar {
}
}
// The user can ⌘-drag the icon off the menubar (enabled by `.removalAllowed`). When that
// happens, `isVisible` flips true→false and we persist the preference. Observing here in
// `Menubar` rather than in `GeneralTab` means we react whether or not Settings is open.
static private func observeRemovalFromMenubar() {
statusItem.behavior = .removalAllowed
isVisibleObserver = statusItem.observe(\.isVisible, options: [.old, .new]) { _, change in
if change.oldValue == true && change.newValue == false {
Preferences.set("menubarIconShown", "false")
GeneralTab.menuIconShownToggle?.setSilently(.off)
}
}
}
private static var badgeDotLayer: CALayer?
static private func loadPreferredIcon() {
@@ -3,20 +3,20 @@ import Sparkle
class GeneralTab {
static var menubarIconDropdown: NSPopUpButton?
static var menuIconShownToggle: Switch?
static var updatesPolicyDropdown: NSPopUpButton?
static var crashPolicyDropdown: NSPopUpButton?
static var policyLock = false
private static var menubarIsVisibleObserver: NSKeyValueObservation?
static func initTab() -> NSView {
let startAtLogin = TableGroupView.Row(leftTitle: NSLocalizedString("Start at login", comment: ""),
rightViews: [LabelAndControl.makeSwitch("startAtLogin")])
menubarIconDropdown = LabelAndControl.makeDropdown("menubarIcon", MenubarIconPreference.allCases)
let menuIconShownToggle = LabelAndControl.makeSwitch("menubarIconShown")
menuIconShownToggle = LabelAndControl.makeSwitch("menubarIconShown")
let menubarIcon = TableGroupView.Row(leftTitle: NSLocalizedString("Menubar icon", comment: ""),
rightViews: [
menubarIconDropdown!,
menuIconShownToggle,
menuIconShownToggle!,
])
let language = TableGroupView.Row(leftTitle: NSLocalizedString("Language", comment: ""),
rightViews: [LabelAndControl.makeDropdown("language", LanguagePreference.allCases, extraAction: setLanguageCallback)])
@@ -36,7 +36,6 @@ class GeneralTab {
cell.bezelStyle = .regularSquare
cell.arrowPosition = .arrowAtBottom
cell.imagePosition = .imageOverlaps
enableDraggingOffMenubarIcon(menuIconShownToggle)
let captureWindowsInBackground = TableGroupView.Row(leftTitle: NSLocalizedString("Capture windows in the background", comment: ""),
subTitle: NSLocalizedString("When disabled, avoids the macOS purple screen-recording indicator, and avoids flickers when playing DRM video. Thumbnails will be less up-to-date.", comment: ""),
rightViews: [LabelAndControl.makeSwitch("captureWindowsInBackground")])
@@ -67,9 +66,8 @@ class GeneralTab {
}
static func cleanup() {
// KVO observer is invalidated by nil-out
menubarIsVisibleObserver = nil
menubarIconDropdown = nil
menuIconShownToggle = nil
updatesPolicyDropdown = nil
crashPolicyDropdown = nil
}
@@ -81,17 +79,6 @@ class GeneralTab {
crashPolicyDropdown?.selectItem(at: CachedUserDefaults.intFromMacroPref("crashPolicy", CrashPolicyPreference.allCases))
}
private static func enableDraggingOffMenubarIcon(_ menuIconShownToggle: Switch) {
Menubar.statusItem.behavior = .removalAllowed
menubarIsVisibleObserver = Menubar.statusItem.observe(\.isVisible, options: [.old, .new]) { _, change in
Logger.debug { "---- \(change)" }
if change.oldValue == true && change.newValue == false {
menuIconShownToggle.state = .off
LabelAndControl.controlWasChanged(menuIconShownToggle, nil)
}
}
}
@objc static func resetPreferences() {
let alert = NSAlert()
alert.alertStyle = .critical