Summary
Every time a provider is enabled or disabled, all menu bar icons jump back to the leftmost position, losing the custom position set via Cmd+Drag.
Steps to Reproduce
- Launch CodexBar with 2+ providers enabled (separate icon mode, not merged)
- Cmd+Drag the icons to a custom position in the menu bar
- Open Preferences → Providers, enable or disable any provider
- Observe the menu bar
Actual Result
All CodexBar status icons are recreated at the leftmost position. The user's custom arrangement is lost.
Expected Result
Existing icons should stay in their current position. Only newly added icons should appear at the default position.
Root Cause
rebuildProviderStatusItems() in StatusItemController.swift destroys all NSStatusItem instances and recreates them on every provider config change. macOS binds icon position to the NSStatusItem instance — once destroyed, the position is lost.
Additionally, NSStatusItem.autosaveName is never set, so macOS cannot persist and restore icon positions across app launches.
Suggested Fix
Two changes to Sources/CodexBar/StatusItemController.swift:
1. Set autosaveName on all NSStatusItem instances
Use stable identifiers ("codexbar-merged" for merged mode, "codexbar-{provider.rawValue}" for individual providers) so macOS can automatically persist positions via its built-in autosaveName mechanism (macOS 12+).
Three creation sites need this: init (merged item), lazyStatusItem(for:), and rebuildProviderStatusItems().
2. Incremental update in rebuildProviderStatusItems()
Replace the full destroy-and-recreate loop with incremental logic:
- Only remove items for providers no longer in the desired set
- Reuse existing items (do not touch them)
- Only create items for newly added providers
private func rebuildProviderStatusItems() {
let desiredOrder = self.settings.orderedProviders()
let desiredSet = Set(desiredOrder)
for (provider, item) in self.statusItems where !desiredSet.contains(provider) {
self.statusBar.removeStatusItem(item)
self.statusItems.removeValue(forKey: provider)
}
for provider in desiredOrder {
if self.statusItems[provider] == nil {
let item = self.statusBar.statusItem(withLength: NSStatusItem.variableLength)
item.button?.imageScaling = .scaleNone
item.autosaveName = "codexbar-\(provider.rawValue)"
self.statusItems[provider] = item
}
}
}
Environment
- CodexBar: 0.18.0 / main branch (commit
f65017c)
- macOS: 14.8.4 (Apple M3 Pro)
Note: I'm currently unable to run swift build / swift test since my macOS version doesn't yet support the required Swift 6.2
toolchain. Will follow up with build verification once my environment permits.
Summary
Every time a provider is enabled or disabled, all menu bar icons jump back to the leftmost position, losing the custom position set via Cmd+Drag.
Steps to Reproduce
Actual Result
All CodexBar status icons are recreated at the leftmost position. The user's custom arrangement is lost.
Expected Result
Existing icons should stay in their current position. Only newly added icons should appear at the default position.
Root Cause
rebuildProviderStatusItems()inStatusItemController.swiftdestroys allNSStatusIteminstances and recreates them on every provider config change. macOS binds icon position to theNSStatusIteminstance — once destroyed, the position is lost.Additionally,
NSStatusItem.autosaveNameis never set, so macOS cannot persist and restore icon positions across app launches.Suggested Fix
Two changes to
Sources/CodexBar/StatusItemController.swift:1. Set
autosaveNameon all NSStatusItem instancesUse stable identifiers (
"codexbar-merged"for merged mode,"codexbar-{provider.rawValue}"for individual providers) so macOS can automatically persist positions via its built-inautosaveNamemechanism (macOS 12+).Three creation sites need this:
init(merged item),lazyStatusItem(for:), andrebuildProviderStatusItems().2. Incremental update in
rebuildProviderStatusItems()Replace the full destroy-and-recreate loop with incremental logic:
Environment
f65017c)Note: I'm currently unable to run swift build / swift test since my macOS version doesn't yet support the required Swift 6.2
toolchain. Will follow up with build verification once my environment permits.