NSMenuToolbarItem not showing first menu item when using NSMenuDelegate

I am using NSMenuToolbarItem to show a drop-down menu in my NSToolbar. This works as expected when creating an NSMenu beforehand and assign it to the menu property of NSMenuToolbarItem.

However, my menu needs to be built dynamically when the user clicks the dropdown button. To do that, I am using NSMenuDelegate. When creating the menu in the menuNeedsUpdate of the delegate, the first menu item isn't shown to the user. Why?

Menu when using delegate:

Menu when pre-assigning menu:

I also cannot just add a placeholder menu item at the start of the NSMenuToolbarItem as all menu items do show in the overflow menu.

Example code:

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate, NSToolbarDelegate, NSMenuDelegate {
    
    var window: NSWindow!
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 400, height: 300),
                          styleMask: [.titled, .closable, .resizable],
                          backing: .buffered,
                          defer: false)
        window.makeKeyAndOrderFront(nil)
        let toolbar = NSToolbar(identifier: "MainToolbar")
        toolbar.delegate = self
        window.toolbar = toolbar
    }
        
    func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
        return [NSToolbarItem.Identifier("item1"), NSToolbarItem.Identifier("item2")]
    }
    
    func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
        return [NSToolbarItem.Identifier("item1"), NSToolbarItem.Identifier("item2")]
    }
    
    func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier,
                 willBeInsertedIntoToolbar: Bool) -> NSToolbarItem? {
        let item = NSMenuToolbarItem(itemIdentifier: itemIdentifier)
        if itemIdentifier == NSToolbarItem.Identifier("item1") {
            let menu = NSMenu()
            fillMenuWithItems(menu)
            item.menu = menu
        } else if itemIdentifier == NSToolbarItem.Identifier("item2") {
            item.menu = NSMenu()
            item.menu.delegate = self
        }
        return item
    }
    
    func menuNeedsUpdate(_ menu: NSMenu) {
        menu.removeAllItems()
        fillMenuWithItems(menu)
    }
    
    func fillMenuWithItems(_ menu: NSMenu) {
        menu.addItem(NSMenuItem(title: "Option 1", action: nil, keyEquivalent: ""))
        menu.addItem(NSMenuItem(title: "Option 2", action: nil, keyEquivalent: ""))
    }
}

what happens if you add option 3 and option 4 ?

We see 2 menus (down arrow): what are they ? It seems you do not use the same (first or second) in the 2 screenshots; P¨lease explain.

Several questions about this func:

    func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier,
                 willBeInsertedIntoToolbar: Bool) -> NSToolbarItem? {
        let item = NSMenuToolbarItem(itemIdentifier: itemIdentifier)
        if itemIdentifier == NSToolbarItem.Identifier("item1") {
            let menu = NSMenu()
            fillMenuWithItems(menu)
            item.menu = menu
        } else if itemIdentifier == NSToolbarItem.Identifier("item2") {
            item.menu = NSMenu()
            item.menu.delegate = self
        }
        return item
    }

I don't understand what you do here:

  • when calling item1, you create the full menu (fillMenuWithItems) ; and you do not set the delegate
  • but for item2, you do not fill

I would try:

        let item = NSMenuToolbarItem(itemIdentifier: itemIdentifier)
       //  if itemIdentifier == NSToolbarItem.Identifier("item1") {  // <<-- REMOVE
            let menu = NSMenu()
            fillMenuWithItems(menu)
            item.menu = menu
       //  } else if itemIdentifier == NSToolbarItem.Identifier("item2") {  // <<-- REMOVE
       //      item.menu = NSMenu()  // <<-- REMOVE
            item.menu.delegate = self
        // }  // <<-- REMOVE
NSMenuToolbarItem not showing first menu item when using NSMenuDelegate
 
 
Q