Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Sources/CodexBar/StatusItemController+Menu.swift
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,7 @@ extension StatusItemController {
context: MenuRebuildContext)
{
self.performMenuMutationWithoutAnimation {
defer { self.flushHostedMenuRowRendering(in: menu) }
let displacedSelection = self.lastMergedMenuContentSelection
self.lastMergedMenuContentSelection = nil
self.harvestRecyclableMenuCardViews(in: menu, fromIndex: 0, displacedSelection: displacedSelection)
Expand Down
14 changes: 14 additions & 0 deletions Sources/CodexBar/StatusItemController+MenuReconcile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,20 @@ extension StatusItemController {
return displacedItems
}

/// Forces hosted rows to lay out and draw inside the caller's disabled-actions
/// transaction. `NSHostingView` commits SwiftUI updates asynchronously by
/// default, so a provider-tab switch could paint the previous card content for
/// a frame after the item mutation — visible as a brief flicker. Flushing
/// synchronously makes the content swap composite atomically with the menu
/// update. Views without a window (closed or detached menus) are skipped.
func flushHostedMenuRowRendering(in menu: NSMenu) {
for item in menu.items {
guard let view = item.view, view.window != nil else { continue }
view.layoutSubtreeIfNeeded()
view.displayIfNeeded()
}
}

private func finishReconciledHighlightTracking(in menu: NSMenu) {
let menuKey = ObjectIdentifier(menu)
guard let highlightedItem = self.highlightedMenuItems[menuKey] else { return }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ extension StatusItemController {
context: MenuUpdateContext)
{
self.performMenuMutationWithoutAnimation {
defer { self.flushHostedMenuRowRendering(in: menu) }
let contentStartIndex = self.providerSwitcherContentStartIndex(in: menu)
if let switcherView = menu.items.first?.view as? ProviderSwitcherView {
switcherView.updateSelection(context.switcherSelection)
Expand Down