import AppKitimport CodexBarCoreimport Observationimport QuartzCoreimport SwiftUI // MARK: - NSMenu construction extension StatusItemController { static let menuCardBaseWidth: CGFloat = 310 private static let maxOverviewProviders = SettingsStore.mergedOverviewProviderLimit static let overviewRowIdentifierPrefix = "overviewRow-" static let persistentRefreshMenuItemID = "persistentRefreshAction" private static let defaultMenuOpenRefreshDelay: Duration = .seconds(1.2) #if DEBUG private static var menuOpenRefreshDelayForTesting: Duration = .seconds(1.2) static func setMenuOpenRefreshDelayForTesting(_ delay: Duration) { self.menuOpenRefreshDelayForTesting = delay } static func resetMenuOpenRefreshDelayForTesting() { self.menuOpenRefreshDelayForTesting = self.defaultMenuOpenRefreshDelay } #endif private static var menuOpenRefreshDelay: Duration { #if DEBUG menuOpenRefreshDelayForTesting #else defaultMenuOpenRefreshDelay #endif } static let usageBreakdownChartID = "usageBreakdownChart" static let creditsHistoryChartID = "creditsHistoryChart" static let costHistoryChartID = "costHistoryChart" static let usageHistoryChartID = "usageHistoryChart" static let storageBreakdownID = "storageBreakdown" static let statusComponentsID = "statusComponents" func shortcut(for action: MenuDescriptor.MenuAction) -> (key: String, modifiers: NSEvent.ModifierFlags)? { switch action { case .refresh: ("r", [.command]) case .settings: (",", [.command]) case .quit: ("q", [.command]) default: nil } } func makeMenu() -> NSMenu { guard self.shouldMergeIcons else { return self.makeMenu(for: nil) } return self.makeBaseMenu() } func menuNeedsUpdate(_ menu: NSMenu) { guard self.shouldMergeIcons, menu === self.mergedMenu else { return } self.refreshMenuForOpenIfNeeded(menu, provider: self.resolvedMenuProvider()) } func menuWillOpen(_ menu: NSMenu) { // Records interaction and may bring an adaptive timer forward; never refreshes synchronously. self.store.noteMenuOpened() self.agentSessions.refreshOnMenuOpen() let trace = self.beginMenuOperationTrace("menuWillOpen", breadcrumb: "menuWillOpen") defer { self.endMenuOperationTrace(trace, menu: menu, provider: self.menuProvider(for: menu)) } // Keep the menu drawing in the current system appearance rather than the menu bar's // (possibly dark) vibrant appearance. Done before any early return so submenus match too. StatusMenuAppearance.pin(menu) self.cancelDeferredMenuInteractionRefreshTask() self.cancelClosedMenuRebuild(menu) self.beginMenuTrackingSession(for: menu) // Track whether this is the root menu opening (no menus were open). Only the root open rebuilds // all content from current data, so the readiness baseline is re-anchored only here — re-anchoring // on a nested submenu open could mask a pending refresh for the already-open parent menu. let menuTrackingWasIdle = self.openMenus.isEmpty if self.isHostedSubviewMenu(menu) { if !self.hydrateHostedSubviewMenuIfNeeded(menu) { self.refreshHostedSubviewMenu(menu) } if self.isMenuRefreshEnabled, self.isOpenAIWebSubviewMenu(menu) { self.deferOpenAIDashboardRefreshUntilMenuCloses(reason: "submenu open") } if self.isMenuRefreshEnabled { // Intentionally skip open-menu tracking when refresh is disabled (tests). // If refresh is re-enabled while this menu stays open, it will not be backfilled until next open. self.openMenus[ObjectIdentifier(menu)] = menu if menuTrackingWasIdle { self.resyncMenuAdjunctReadinessBaseline() } } // Removed redundant async refresh - single pass is sufficient after initial layout return } var provider: UsageProvider? if self.shouldMergeIcons { let resolvedProvider = self.resolvedMenuProvider() self.lastMenuProvider = resolvedProvider ?? .codex provider = resolvedProvider } else { if let menuProvider = self.menuProviders[ObjectIdentifier(menu)] { self.lastMenuProvider = menuProvider provider = menuProvider } else if menu === self.fallbackMenu { self.lastMenuProvider = self.store.enabledProvidersForDisplay().first ?? .codex provider = nil } else { let resolved = self.store.enabledProvidersForDisplay().first ?? .codex self.lastMenuProvider = resolved provider = resolved } } if self.isMenuRefreshEnabled, (provider ?? self.lastMenuProvider) == .codex { self.deferOpenAIDashboardRefreshUntilMenuCloses(reason: "parent menu open") } if self.settings.providerStorageFootprintsEnabled { self.store.refreshStorageFootprintsForOverview() } let menuWasFreshBeforeOpen = !self.menuNeedsRefresh(menu) self.refreshMenuForOpenIfNeeded(menu, provider: provider) self.scheduleCodexAccountMenuProjectionRevalidationIfNeeded( for: self.renderedProviders(for: menu)) if self.isMenuRefreshEnabled { // Intentionally skip open-menu tracking when refresh is disabled (tests). // If refresh is re-enabled while this menu stays open, it will not be backfilled until next open. self.openMenus[ObjectIdentifier(menu)] = menu // Only re-anchor when the opened menu actually shows current data. During an in-flight provider // refresh `refreshMenuForOpenIfNeeded` can preserve stale content; resyncing the baseline to // live store data in that case would mask the refresh-completion update (#1351). if menuTrackingWasIdle, !self.menuNeedsRefresh(menu) { self.resyncMenuAdjunctReadinessBaselineForRootOpen( menu, provider: provider, menuWasFreshBeforeOpen: menuWasFreshBeforeOpen) } self.installProviderSwitcherShortcutMonitorIfNeeded(for: menu) // Only schedule refresh after menu is registered as open - refreshNow is called async self.scheduleOpenMenuRefresh(for: menu) } } func menuDidClose(_ menu: NSMenu) { let wasHostedSubviewMenu = self.isHostedSubviewMenu(menu) self.forgetClosedMenu(menu) if wasHostedSubviewMenu { self.refreshOpenMenusAfterHostedSubviewClose() } } func forgetClosedMenu(_ menu: NSMenu) { let key = ObjectIdentifier(menu) let wasMergedMenu = menu === self.mergedMenu self.endMenuTrackingSession(for: menu) if key == self.providerSwitcherShortcutMenuID { self.removeProviderSwitcherShortcutMonitor() } self.clearMergedSwitcherContentCache(for: menu) let wasTracked = self.openMenus.removeValue(forKey: key) != nil let menuTrackingEnded = wasTracked && self.openMenus.isEmpty if self.openMenus.isEmpty { self.parentMenuRebuildPendingAfterHostedSubviewClose = false } self.cancelMenuWork(key) self.clearMenuHighlight(key) let isPersistentMenu = menu === self.mergedMenu || menu === self.fallbackMenu || self.providerMenus.values.contains { $0 === menu } if !isPersistentMenu { self.removeMenuTrackingState(key) } else if self.menuNeedsRefresh(menu) { self.handleClosedPersistentMenuNeedingRefresh(menu) } self.menuSession.clearParentRebuildDeferral(key) self.scheduleDeferredMenuInteractionRefreshIfNeeded() if wasMergedMenu { self.applyDeferredMergedIconRenderAfterTrackingIfNeeded() } if menuTrackingEnded { self.prepareAttachedClosedMenusIfNeeded() } } func menu(_ menu: NSMenu, willHighlight item: NSMenuItem?) { let key = ObjectIdentifier(menu) let previous = self.highlightedMenuItems[key] guard previous !== item else { return } let previousWasNative = self.isNativeMenuItemHighlighted(in: menu) if let previous { (previous.view as? MenuCardHighlighting)?.setHighlighted(false) } if let item, item.isEnabled, (item.view as? MenuCardHighlighting)?.allowsMenuHighlight != false { self.highlightedMenuItems[key] = item (item.view as? MenuCardHighlighting)?.setHighlighted(true) } else { self.highlightedMenuItems.removeValue(forKey: key) } if previousWasNative, !self.isNativeMenuItemHighlighted(in: menu) { self.resumeMenuRebuildDeferredForNativeHighlightIfNeeded(menu) } } func populateMenu(_ menu: NSMenu, provider: UsageProvider?) { let trace = self.beginMenuOperationTrace( "populateMenu", breadcrumb: "populateMenu:\(provider?.rawValue ?? "merged")") defer { self.endMenuOperationTrace(trace, menu: menu, provider: provider) } defer { self.refreshMenuCardHeights(in: menu) } let enabledProviders = self.store.enabledProvidersForDisplay() let includesOverview = self.includesOverviewTab(enabledProviders: enabledProviders) let switcherSelection = self.shouldMergeIcons && enabledProviders.count > 1 ? self.resolvedSwitcherSelection( enabledProviders: enabledProviders, includesOverview: includesOverview) : nil let isOverviewSelected = switcherSelection == .overview let selectedProvider = if isOverviewSelected { self.resolvedMenuProvider(enabledProviders: enabledProviders) } else { switcherSelection?.provider ?? provider } let currentProvider = selectedProvider ?? enabledProviders.first ?? .codex let rawCodexAccountDisplay = isOverviewSelected ? nil : self.codexAccountMenuDisplay(for: currentProvider) let codexAccountDisplay = isOverviewSelected ? nil : self.stableCodexAccountMenuDisplay( rawCodexAccountDisplay, menu: menu, provider: currentProvider) let tokenAccountDisplay = isOverviewSelected ? nil : self.tokenAccountMenuDisplay(for: currentProvider) let showAllAccounts = (tokenAccountDisplay?.showAll ?? false) || (codexAccountDisplay?.showAll ?? false) let openAIContext = self.openAIWebContext( currentProvider: currentProvider, showAllAccounts: showAllAccounts) let descriptor = self.makeMenuDescriptor( provider: selectedProvider, includeContextualActions: !isOverviewSelected) let menuWidth = self.menuCardWidth( for: enabledProviders, selectedProvider: selectedProvider, descriptor: descriptor) let hasTokenSwitcher = menu.items.contains { $0.view is TokenAccountSwitcherView } let hasCodexSwitcher = menu.items.contains { $0.view is CodexAccountSwitcherView } let switcherProvidersMatch = enabledProviders == self.lastSwitcherProviders let switcherUsageBarsShowUsedMatch = self.settings.usageBarsShowUsed == self.lastSwitcherUsageBarsShowUsed let switcherSelectionMatches = switcherSelection == self.lastMergedSwitcherSelection let switcherOverviewAvailabilityMatches = includesOverview == self.lastSwitcherIncludesOverview let menuLocalizationMatches = self.menuLocalizationSignature() == self.lastMenuLocalizationSignature let tokenSwitcherCompatible = tokenAccountDisplay == self.lastTokenAccountMenuDisplay && ((tokenAccountDisplay?.showSwitcher == true && hasTokenSwitcher) || (tokenAccountDisplay?.showSwitcher != true && !hasTokenSwitcher)) let codexSwitcherCompatible = codexAccountDisplay == self.lastCodexAccountMenuDisplay && ((codexAccountDisplay?.showSwitcher == true && hasCodexSwitcher) || (codexAccountDisplay?.showSwitcher != true && !hasCodexSwitcher)) let reusableRowWidthsMatch = self.reusableFixedWidthRows(in: menu).allSatisfy { item in guard let view = item.view else { return false } return abs(view.frame.width - menuWidth) <= 0.5 } let providerSwitcherWidthMatches = (menu.items.first?.view as? ProviderSwitcherView).map { view in abs(view.frame.width - menuWidth) <= 0.5 } ?? false let canSmartUpdate = self.shouldMergeIcons && enabledProviders.count > 1 && !isOverviewSelected && switcherProvidersMatch && switcherUsageBarsShowUsedMatch && switcherSelectionMatches && switcherOverviewAvailabilityMatches && menuLocalizationMatches && tokenSwitcherCompatible && codexSwitcherCompatible && reusableRowWidthsMatch && !menu.items.isEmpty && menu.items.first?.view is ProviderSwitcherView #if DEBUG if self.openMenus[ObjectIdentifier(menu)] != nil { self.menuLogger.debug( "populateMenu(open): provider=\(String(describing: provider)) " + "display=\(enabledProviders.map(\.rawValue)) " + "available=\(self.store.enabledProviders().map(\.rawValue)) " + "selection=\(String(describing: switcherSelection)) " + "last=\(String(describing: self.lastMergedSwitcherSelection)) " + "smart=\(canSmartUpdate)") } #endif if canSmartUpdate { self.updateMenuContentPreservingSwitcher( menu, context: MenuUpdateContext( provider: selectedProvider, currentProvider: currentProvider, switcherSelection: switcherSelection ?? .provider(currentProvider), menuWidth: menuWidth, codexAccountDisplay: codexAccountDisplay, tokenAccountDisplay: tokenAccountDisplay, openAIContext: openAIContext, descriptor: descriptor)) return } let canPreserveProviderSwitcher = self.shouldMergeIcons && enabledProviders.count > 1 && switcherProvidersMatch && switcherUsageBarsShowUsedMatch && switcherOverviewAvailabilityMatches && menuLocalizationMatches && providerSwitcherWidthMatches && !menu.items.isEmpty && menu.items.first?.view is ProviderSwitcherView #if DEBUG if self.openMenus[ObjectIdentifier(menu)] != nil { self.menuLogger.debug( "populateMenu(open): preserveSwitcher=\(canPreserveProviderSwitcher) " + "widthMatch=\(providerSwitcherWidthMatches)") } #endif if canPreserveProviderSwitcher { self.updateMenuContentPreservingSwitcher( menu, context: MenuUpdateContext( provider: selectedProvider, currentProvider: currentProvider, switcherSelection: switcherSelection ?? .provider(currentProvider), menuWidth: menuWidth, codexAccountDisplay: codexAccountDisplay, tokenAccountDisplay: tokenAccountDisplay, openAIContext: openAIContext, descriptor: descriptor)) return } #if DEBUG if self.openMenus[ObjectIdentifier(menu)] != nil, menu.items.first?.view is ProviderSwitcherView { self.menuLogger.debug("populateMenu(open): rebuilding whole menu and replacing provider switcher") } #endif self.rebuildMenuContent( menu, context: MenuRebuildContext( enabledProviders: enabledProviders, includesOverview: includesOverview, switcherSelection: switcherSelection, currentProvider: currentProvider, selectedProvider: selectedProvider, menuWidth: menuWidth, codexAccountDisplay: codexAccountDisplay, tokenAccountDisplay: tokenAccountDisplay, openAIContext: openAIContext, descriptor: descriptor)) } private func reusableFixedWidthRows(in menu: NSMenu) -> [NSMenuItem] { guard !menu.items.isEmpty else { return [] } var reusableRows: [NSMenuItem] = [] var index = self.providerSwitcherContentStartIndex(in: menu) if index > 0 { reusableRows.append(menu.items[0]) } if menu.items.count > index, menu.items[index].view is CodexAccountSwitcherView { reusableRows.append(menu.items[index]) index += 2 } if menu.items.count > index, menu.items[index].view is TokenAccountSwitcherView { reusableRows.append(menu.items[index]) } return reusableRows } private func rebuildMenuContent( _ menu: NSMenu, context: MenuRebuildContext) { self.performMenuMutationWithoutAnimation { let displacedSelection = self.lastMergedMenuContentSelection self.lastMergedMenuContentSelection = nil self.harvestRecyclableMenuCardViews(in: menu, fromIndex: 0, displacedSelection: displacedSelection) defer { self.clearMenuCardViewRecyclePool() } menu.removeAllItems() let contentSelection = context.switcherSelection ?? .provider(context.currentProvider) self.addProviderSwitcherIfNeeded( to: menu, enabledProviders: context.enabledProviders, includesOverview: context.includesOverview, selection: context.switcherSelection ?? .provider(context.currentProvider), width: context.menuWidth) // Track which providers the switcher was built with for smart update detection if self.shouldMergeIcons, context.enabledProviders.count > 1 { self.rememberMergedSwitcherState( context.enabledProviders, context.switcherSelection, context.includesOverview) } if self.shouldMergeIcons, context.enabledProviders.count > 1, self.addCachedMergedSwitcherContent( for: contentSelection, to: menu, menuWidth: context.menuWidth, codexAccountDisplay: context.codexAccountDisplay, tokenAccountDisplay: context.tokenAccountDisplay) { return } self.addCodexAccountSwitcherIfNeeded( to: menu, display: context.codexAccountDisplay, width: context.menuWidth) self.lastCodexAccountMenuDisplay = context.codexAccountDisplay self.addTokenAccountSwitcherIfNeeded( to: menu, display: context.tokenAccountDisplay, width: context.menuWidth) self.lastTokenAccountMenuDisplay = context.tokenAccountDisplay let menuContext = MenuCardContext( currentProvider: context.currentProvider, selectedProvider: context.selectedProvider, menuWidth: context.menuWidth, codexAccountDisplay: context.codexAccountDisplay, tokenAccountDisplay: context.tokenAccountDisplay, openAIContext: context.openAIContext) self.addPrimaryMenuContent( to: menu, context: menuContext, switcherSelection: contentSelection) self.addActionableSections(context.descriptor.sections, to: menu, width: context.menuWidth) self.cacheVisibleMergedSwitcherContent( in: menu, selection: contentSelection, contentStartIndex: self.providerSwitcherContentStartIndex(in: menu), menuWidth: context.menuWidth, contentVersion: self.menuSession.contentVersion) } } private func openAIWebContext( currentProvider: UsageProvider, showAllAccounts: Bool) -> OpenAIWebContext { let codexProjection = self.store.codexConsumerProjectionIfNeeded( for: currentProvider, surface: .liveCard) let hasCreditsHistory = codexProjection?.hasCreditsHistory == true let hasUsageBreakdown = codexProjection?.hasUsageBreakdown == true let hasCostHistory = self.settings.costSummaryShowsSubmenu(for: currentProvider) && (self.store.tokenSnapshot(for: currentProvider)?.daily.isEmpty == false) let canShowBuyCredits = self.settings.showOptionalCreditsAndExtraUsage && codexProjection?.canShowBuyCredits == true let hasOpenAIWebMenuItems = !showAllAccounts && (hasCreditsHistory || hasUsageBreakdown || hasCostHistory) return OpenAIWebContext( hasUsageBreakdown: hasUsageBreakdown, hasCreditsHistory: hasCreditsHistory, hasCostHistory: hasCostHistory, canShowBuyCredits: canShowBuyCredits, hasOpenAIWebMenuItems: hasOpenAIWebMenuItems) } private func addProviderSwitcherIfNeeded( to menu: NSMenu, enabledProviders: [UsageProvider], includesOverview: Bool, selection: ProviderSwitcherSelection, width: CGFloat) { guard self.shouldMergeIcons, enabledProviders.count > 1 else { return } let switcherItem = self.makeProviderSwitcherItem(Lines 1–500 of 1659. Load more
import AppKit import CodexBarCore import Observation import QuartzCore import SwiftUI // MARK: - NSMenu construction extension StatusItemController { static let menuCardBaseWidth: CGFloat = 310 private static let maxOverviewProviders = SettingsStore.mergedOverviewProviderLimit static let overviewRowIdentifierPrefix = "overviewRow-" static let persistentRefreshMenuItemID = "persistentRefreshAction" private static let defaultMenuOpenRefreshDelay: Duration = .seconds(1.2) #if DEBUG private static var menuOpenRefreshDelayForTesting: Duration = .seconds(1.2) static func setMenuOpenRefreshDelayForTesting(_ delay: Duration) { self.menuOpenRefreshDelayForTesting = delay } static func resetMenuOpenRefreshDelayForTesting() { self.menuOpenRefreshDelayForTesting = self.defaultMenuOpenRefreshDelay } #endif private static var menuOpenRefreshDelay: Duration { #if DEBUG menuOpenRefreshDelayForTesting #else defaultMenuOpenRefreshDelay #endif } static let usageBreakdownChartID = "usageBreakdownChart" static let creditsHistoryChartID = "creditsHistoryChart" static let costHistoryChartID = "costHistoryChart" static let usageHistoryChartID = "usageHistoryChart" static let storageBreakdownID = "storageBreakdown" static let statusComponentsID = "statusComponents" func shortcut(for action: MenuDescriptor.MenuAction) -> (key: String, modifiers: NSEvent.ModifierFlags)? { switch action { case .refresh: ("r", [.command]) case .settings: (",", [.command]) case .quit: ("q", [.command]) default: nil } } func makeMenu() -> NSMenu { guard self.shouldMergeIcons else { return self.makeMenu(for: nil) } return self.makeBaseMenu() } func menuNeedsUpdate(_ menu: NSMenu) { guard self.shouldMergeIcons, menu === self.mergedMenu else { return } self.refreshMenuForOpenIfNeeded(menu, provider: self.resolvedMenuProvider()) } func menuWillOpen(_ menu: NSMenu) { // Records interaction and may bring an adaptive timer forward; never refreshes synchronously. self.store.noteMenuOpened() self.agentSessions.refreshOnMenuOpen() let trace = self.beginMenuOperationTrace("menuWillOpen", breadcrumb: "menuWillOpen") defer { self.endMenuOperationTrace(trace, menu: menu, provider: self.menuProvider(for: menu)) } // Keep the menu drawing in the current system appearance rather than the menu bar's // (possibly dark) vibrant appearance. Done before any early return so submenus match too. StatusMenuAppearance.pin(menu) self.cancelDeferredMenuInteractionRefreshTask() self.cancelClosedMenuRebuild(menu) self.beginMenuTrackingSession(for: menu) // Track whether this is the root menu opening (no menus were open). Only the root open rebuilds // all content from current data, so the readiness baseline is re-anchored only here — re-anchoring // on a nested submenu open could mask a pending refresh for the already-open parent menu. let menuTrackingWasIdle = self.openMenus.isEmpty if self.isHostedSubviewMenu(menu) { if !self.hydrateHostedSubviewMenuIfNeeded(menu) { self.refreshHostedSubviewMenu(menu) } if self.isMenuRefreshEnabled, self.isOpenAIWebSubviewMenu(menu) { self.deferOpenAIDashboardRefreshUntilMenuCloses(reason: "submenu open") } if self.isMenuRefreshEnabled { // Intentionally skip open-menu tracking when refresh is disabled (tests). // If refresh is re-enabled while this menu stays open, it will not be backfilled until next open. self.openMenus[ObjectIdentifier(menu)] = menu if menuTrackingWasIdle { self.resyncMenuAdjunctReadinessBaseline() } } // Removed redundant async refresh - single pass is sufficient after initial layout return } var provider: UsageProvider? if self.shouldMergeIcons { let resolvedProvider = self.resolvedMenuProvider() self.lastMenuProvider = resolvedProvider ?? .codex provider = resolvedProvider } else { if let menuProvider = self.menuProviders[ObjectIdentifier(menu)] { self.lastMenuProvider = menuProvider provider = menuProvider } else if menu === self.fallbackMenu { self.lastMenuProvider = self.store.enabledProvidersForDisplay().first ?? .codex provider = nil } else { let resolved = self.store.enabledProvidersForDisplay().first ?? .codex self.lastMenuProvider = resolved provider = resolved } } if self.isMenuRefreshEnabled, (provider ?? self.lastMenuProvider) == .codex { self.deferOpenAIDashboardRefreshUntilMenuCloses(reason: "parent menu open") } if self.settings.providerStorageFootprintsEnabled { self.store.refreshStorageFootprintsForOverview() } let menuWasFreshBeforeOpen = !self.menuNeedsRefresh(menu) self.refreshMenuForOpenIfNeeded(menu, provider: provider) self.scheduleCodexAccountMenuProjectionRevalidationIfNeeded( for: self.renderedProviders(for: menu)) if self.isMenuRefreshEnabled { // Intentionally skip open-menu tracking when refresh is disabled (tests). // If refresh is re-enabled while this menu stays open, it will not be backfilled until next open. self.openMenus[ObjectIdentifier(menu)] = menu // Only re-anchor when the opened menu actually shows current data. During an in-flight provider // refresh `refreshMenuForOpenIfNeeded` can preserve stale content; resyncing the baseline to // live store data in that case would mask the refresh-completion update (#1351). if menuTrackingWasIdle, !self.menuNeedsRefresh(menu) { self.resyncMenuAdjunctReadinessBaselineForRootOpen( menu, provider: provider, menuWasFreshBeforeOpen: menuWasFreshBeforeOpen) } self.installProviderSwitcherShortcutMonitorIfNeeded(for: menu) // Only schedule refresh after menu is registered as open - refreshNow is called async self.scheduleOpenMenuRefresh(for: menu) } } func menuDidClose(_ menu: NSMenu) { let wasHostedSubviewMenu = self.isHostedSubviewMenu(menu) self.forgetClosedMenu(menu) if wasHostedSubviewMenu { self.refreshOpenMenusAfterHostedSubviewClose() } } func forgetClosedMenu(_ menu: NSMenu) { let key = ObjectIdentifier(menu) let wasMergedMenu = menu === self.mergedMenu self.endMenuTrackingSession(for: menu) if key == self.providerSwitcherShortcutMenuID { self.removeProviderSwitcherShortcutMonitor() } self.clearMergedSwitcherContentCache(for: menu) let wasTracked = self.openMenus.removeValue(forKey: key) != nil let menuTrackingEnded = wasTracked && self.openMenus.isEmpty if self.openMenus.isEmpty { self.parentMenuRebuildPendingAfterHostedSubviewClose = false } self.cancelMenuWork(key) self.clearMenuHighlight(key) let isPersistentMenu = menu === self.mergedMenu || menu === self.fallbackMenu || self.providerMenus.values.contains { $0 === menu } if !isPersistentMenu { self.removeMenuTrackingState(key) } else if self.menuNeedsRefresh(menu) { self.handleClosedPersistentMenuNeedingRefresh(menu) } self.menuSession.clearParentRebuildDeferral(key) self.scheduleDeferredMenuInteractionRefreshIfNeeded() if wasMergedMenu { self.applyDeferredMergedIconRenderAfterTrackingIfNeeded() } if menuTrackingEnded { self.prepareAttachedClosedMenusIfNeeded() } } func menu(_ menu: NSMenu, willHighlight item: NSMenuItem?) { let key = ObjectIdentifier(menu) let previous = self.highlightedMenuItems[key] guard previous !== item else { return } let previousWasNative = self.isNativeMenuItemHighlighted(in: menu) if let previous { (previous.view as? MenuCardHighlighting)?.setHighlighted(false) } if let item, item.isEnabled, (item.view as? MenuCardHighlighting)?.allowsMenuHighlight != false { self.highlightedMenuItems[key] = item (item.view as? MenuCardHighlighting)?.setHighlighted(true) } else { self.highlightedMenuItems.removeValue(forKey: key) } if previousWasNative, !self.isNativeMenuItemHighlighted(in: menu) { self.resumeMenuRebuildDeferredForNativeHighlightIfNeeded(menu) } } func populateMenu(_ menu: NSMenu, provider: UsageProvider?) { let trace = self.beginMenuOperationTrace( "populateMenu", breadcrumb: "populateMenu:\(provider?.rawValue ?? "merged")") defer { self.endMenuOperationTrace(trace, menu: menu, provider: provider) } defer { self.refreshMenuCardHeights(in: menu) } let enabledProviders = self.store.enabledProvidersForDisplay() let includesOverview = self.includesOverviewTab(enabledProviders: enabledProviders) let switcherSelection = self.shouldMergeIcons && enabledProviders.count > 1 ? self.resolvedSwitcherSelection( enabledProviders: enabledProviders, includesOverview: includesOverview) : nil let isOverviewSelected = switcherSelection == .overview let selectedProvider = if isOverviewSelected { self.resolvedMenuProvider(enabledProviders: enabledProviders) } else { switcherSelection?.provider ?? provider } let currentProvider = selectedProvider ?? enabledProviders.first ?? .codex let rawCodexAccountDisplay = isOverviewSelected ? nil : self.codexAccountMenuDisplay(for: currentProvider) let codexAccountDisplay = isOverviewSelected ? nil : self.stableCodexAccountMenuDisplay( rawCodexAccountDisplay, menu: menu, provider: currentProvider) let tokenAccountDisplay = isOverviewSelected ? nil : self.tokenAccountMenuDisplay(for: currentProvider) let showAllAccounts = (tokenAccountDisplay?.showAll ?? false) || (codexAccountDisplay?.showAll ?? false) let openAIContext = self.openAIWebContext( currentProvider: currentProvider, showAllAccounts: showAllAccounts) let descriptor = self.makeMenuDescriptor( provider: selectedProvider, includeContextualActions: !isOverviewSelected) let menuWidth = self.menuCardWidth( for: enabledProviders, selectedProvider: selectedProvider, descriptor: descriptor) let hasTokenSwitcher = menu.items.contains { $0.view is TokenAccountSwitcherView } let hasCodexSwitcher = menu.items.contains { $0.view is CodexAccountSwitcherView } let switcherProvidersMatch = enabledProviders == self.lastSwitcherProviders let switcherUsageBarsShowUsedMatch = self.settings.usageBarsShowUsed == self.lastSwitcherUsageBarsShowUsed let switcherSelectionMatches = switcherSelection == self.lastMergedSwitcherSelection let switcherOverviewAvailabilityMatches = includesOverview == self.lastSwitcherIncludesOverview let menuLocalizationMatches = self.menuLocalizationSignature() == self.lastMenuLocalizationSignature let tokenSwitcherCompatible = tokenAccountDisplay == self.lastTokenAccountMenuDisplay && ((tokenAccountDisplay?.showSwitcher == true && hasTokenSwitcher) || (tokenAccountDisplay?.showSwitcher != true && !hasTokenSwitcher)) let codexSwitcherCompatible = codexAccountDisplay == self.lastCodexAccountMenuDisplay && ((codexAccountDisplay?.showSwitcher == true && hasCodexSwitcher) || (codexAccountDisplay?.showSwitcher != true && !hasCodexSwitcher)) let reusableRowWidthsMatch = self.reusableFixedWidthRows(in: menu).allSatisfy { item in guard let view = item.view else { return false } return abs(view.frame.width - menuWidth) <= 0.5 } let providerSwitcherWidthMatches = (menu.items.first?.view as? ProviderSwitcherView).map { view in abs(view.frame.width - menuWidth) <= 0.5 } ?? false let canSmartUpdate = self.shouldMergeIcons && enabledProviders.count > 1 && !isOverviewSelected && switcherProvidersMatch && switcherUsageBarsShowUsedMatch && switcherSelectionMatches && switcherOverviewAvailabilityMatches && menuLocalizationMatches && tokenSwitcherCompatible && codexSwitcherCompatible && reusableRowWidthsMatch && !menu.items.isEmpty && menu.items.first?.view is ProviderSwitcherView #if DEBUG if self.openMenus[ObjectIdentifier(menu)] != nil { self.menuLogger.debug( "populateMenu(open): provider=\(String(describing: provider)) " + "display=\(enabledProviders.map(\.rawValue)) " + "available=\(self.store.enabledProviders().map(\.rawValue)) " + "selection=\(String(describing: switcherSelection)) " + "last=\(String(describing: self.lastMergedSwitcherSelection)) " + "smart=\(canSmartUpdate)") } #endif if canSmartUpdate { self.updateMenuContentPreservingSwitcher( menu, context: MenuUpdateContext( provider: selectedProvider, currentProvider: currentProvider, switcherSelection: switcherSelection ?? .provider(currentProvider), menuWidth: menuWidth, codexAccountDisplay: codexAccountDisplay, tokenAccountDisplay: tokenAccountDisplay, openAIContext: openAIContext, descriptor: descriptor)) return } let canPreserveProviderSwitcher = self.shouldMergeIcons && enabledProviders.count > 1 && switcherProvidersMatch && switcherUsageBarsShowUsedMatch && switcherOverviewAvailabilityMatches && menuLocalizationMatches && providerSwitcherWidthMatches && !menu.items.isEmpty && menu.items.first?.view is ProviderSwitcherView #if DEBUG if self.openMenus[ObjectIdentifier(menu)] != nil { self.menuLogger.debug( "populateMenu(open): preserveSwitcher=\(canPreserveProviderSwitcher) " + "widthMatch=\(providerSwitcherWidthMatches)") } #endif if canPreserveProviderSwitcher { self.updateMenuContentPreservingSwitcher( menu, context: MenuUpdateContext( provider: selectedProvider, currentProvider: currentProvider, switcherSelection: switcherSelection ?? .provider(currentProvider), menuWidth: menuWidth, codexAccountDisplay: codexAccountDisplay, tokenAccountDisplay: tokenAccountDisplay, openAIContext: openAIContext, descriptor: descriptor)) return } #if DEBUG if self.openMenus[ObjectIdentifier(menu)] != nil, menu.items.first?.view is ProviderSwitcherView { self.menuLogger.debug("populateMenu(open): rebuilding whole menu and replacing provider switcher") } #endif self.rebuildMenuContent( menu, context: MenuRebuildContext( enabledProviders: enabledProviders, includesOverview: includesOverview, switcherSelection: switcherSelection, currentProvider: currentProvider, selectedProvider: selectedProvider, menuWidth: menuWidth, codexAccountDisplay: codexAccountDisplay, tokenAccountDisplay: tokenAccountDisplay, openAIContext: openAIContext, descriptor: descriptor)) } private func reusableFixedWidthRows(in menu: NSMenu) -> [NSMenuItem] { guard !menu.items.isEmpty else { return [] } var reusableRows: [NSMenuItem] = [] var index = self.providerSwitcherContentStartIndex(in: menu) if index > 0 { reusableRows.append(menu.items[0]) } if menu.items.count > index, menu.items[index].view is CodexAccountSwitcherView { reusableRows.append(menu.items[index]) index += 2 } if menu.items.count > index, menu.items[index].view is TokenAccountSwitcherView { reusableRows.append(menu.items[index]) } return reusableRows } private func rebuildMenuContent( _ menu: NSMenu, context: MenuRebuildContext) { self.performMenuMutationWithoutAnimation { let displacedSelection = self.lastMergedMenuContentSelection self.lastMergedMenuContentSelection = nil self.harvestRecyclableMenuCardViews(in: menu, fromIndex: 0, displacedSelection: displacedSelection) defer { self.clearMenuCardViewRecyclePool() } menu.removeAllItems() let contentSelection = context.switcherSelection ?? .provider(context.currentProvider) self.addProviderSwitcherIfNeeded( to: menu, enabledProviders: context.enabledProviders, includesOverview: context.includesOverview, selection: context.switcherSelection ?? .provider(context.currentProvider), width: context.menuWidth) // Track which providers the switcher was built with for smart update detection if self.shouldMergeIcons, context.enabledProviders.count > 1 { self.rememberMergedSwitcherState( context.enabledProviders, context.switcherSelection, context.includesOverview) } if self.shouldMergeIcons, context.enabledProviders.count > 1, self.addCachedMergedSwitcherContent( for: contentSelection, to: menu, menuWidth: context.menuWidth, codexAccountDisplay: context.codexAccountDisplay, tokenAccountDisplay: context.tokenAccountDisplay) { return } self.addCodexAccountSwitcherIfNeeded( to: menu, display: context.codexAccountDisplay, width: context.menuWidth) self.lastCodexAccountMenuDisplay = context.codexAccountDisplay self.addTokenAccountSwitcherIfNeeded( to: menu, display: context.tokenAccountDisplay, width: context.menuWidth) self.lastTokenAccountMenuDisplay = context.tokenAccountDisplay let menuContext = MenuCardContext( currentProvider: context.currentProvider, selectedProvider: context.selectedProvider, menuWidth: context.menuWidth, codexAccountDisplay: context.codexAccountDisplay, tokenAccountDisplay: context.tokenAccountDisplay, openAIContext: context.openAIContext) self.addPrimaryMenuContent( to: menu, context: menuContext, switcherSelection: contentSelection) self.addActionableSections(context.descriptor.sections, to: menu, width: context.menuWidth) self.cacheVisibleMergedSwitcherContent( in: menu, selection: contentSelection, contentStartIndex: self.providerSwitcherContentStartIndex(in: menu), menuWidth: context.menuWidth, contentVersion: self.menuSession.contentVersion) } } private func openAIWebContext( currentProvider: UsageProvider, showAllAccounts: Bool) -> OpenAIWebContext { let codexProjection = self.store.codexConsumerProjectionIfNeeded( for: currentProvider, surface: .liveCard) let hasCreditsHistory = codexProjection?.hasCreditsHistory == true let hasUsageBreakdown = codexProjection?.hasUsageBreakdown == true let hasCostHistory = self.settings.costSummaryShowsSubmenu(for: currentProvider) && (self.store.tokenSnapshot(for: currentProvider)?.daily.isEmpty == false) let canShowBuyCredits = self.settings.showOptionalCreditsAndExtraUsage && codexProjection?.canShowBuyCredits == true let hasOpenAIWebMenuItems = !showAllAccounts && (hasCreditsHistory || hasUsageBreakdown || hasCostHistory) return OpenAIWebContext( hasUsageBreakdown: hasUsageBreakdown, hasCreditsHistory: hasCreditsHistory, hasCostHistory: hasCostHistory, canShowBuyCredits: canShowBuyCredits, hasOpenAIWebMenuItems: hasOpenAIWebMenuItems) } private func addProviderSwitcherIfNeeded( to menu: NSMenu, enabledProviders: [UsageProvider], includesOverview: Bool, selection: ProviderSwitcherSelection, width: CGFloat) { guard self.shouldMergeIcons, enabledProviders.count > 1 else { return } let switcherItem = self.makeProviderSwitcherItem(