SystemTrayIconComponent OSX native menus broken in 5.00 working in 4.3.1

I’ve just returned to an unfinished project which last worked ( and was being worked on ) in JUCE version 4.3.1.

It used SystemTrayIconComponent to implement an OSX menu-extra dropdown menu and was all working fine. But in 5.00 the native code in JUCE seems to have been changed considerably and I get an assertion error as soon as the system tray icon is clicked.

in juice_mac-MainMenu.mm in JUCE 4.3.1 function menuNeedsUpdate() calls instance->updateMenus (menu);

but in 5.00 onwards a call is made to a new version of updateTopLevelMenu() as follows:

void updateTopLevelMenu (NSMenu* menu)
{
NSMenu* superMenu = [menu supermenu];
auto menuNames = currentModel->getMenuBarNames();
auto indexOfMenu = (int) [superMenu indexOfItemWithSubmenu: menu] - 1;

    removeItemRecursive (menu);

    auto updatedPopup = currentModel->getMenuForIndex (indexOfMenu, menuNames[indexOfMenu]);

    for (PopupMenu::MenuItemIterator iter (updatedPopup); iter.next();)
        addMenuItem (iter, menu, 1, indexOfMenu);

    [menu update];
}

but this is generating an assertion because superMenu is nil. and thus indexOfMenu. is -1 - and because of this - the subsequent MenuBarModel method getMenuForIndex() fails.

I don’t know at this stage whether this requires a bugfix from your JUCE team or whether I need to do something different. but currently I don’t see any GUI examples in your JUCE Demo app which uses native OSX menus. For the SystemTrayIcon.

This was working in Juce 4 and is now broken in 5

Hmmm strange, the JUCE demo has a DemoTaskbarComponent and it seems to work well: I can’t seem to reproduce the assertion that you are seeing.

Yes but that demo uses a JUCE menu - its a black rectangle drop-down. It doesn’t use native OSX menus at all.

But the code does ( or should ) exist in JUCE to use native menu-extras style dropdown - since I was the person who requested it ( and used it successfully until now ).

This is the code in your DemoTaskbarComponent :

void timerCallback() override
{
stopTimer();

    PopupMenu m;
    m.addItem (1, "Quit the JUCE demo");

    // It's always better to open menus asynchronously when possible.
    m.showMenuAsync (PopupMenu::Options(),
                     ModalCallbackFunction::forComponent (menuInvocationCallback, this));
}

/////////. and this is the salient bits of mine -

void MenuExtra::timerCallback()
{

    stopTimer();
    showDropdownMenu(*getPopupMenu());

}

void SystemTrayIconComponent::showDropdownMenu (const PopupMenu& menu)
{
if (pimpl != nullptr)
pimpl->showMenu (menu); // this ( on 4.3 ) populates a OSX native menu using contents of ‘menu’ as template info
}

my code calls this - in juce_mac_SystemTrayIcon.cpp - which the Demo example doesn’t.

void showMenu (const PopupMenu& menu)
{
    if (NSMenu* m = createNSMenu (menu, "MenuBarItem", -2, -3, true))
    {
        setHighlighted (true);
        stopTimer();
        [statusItem popUpStatusItemMenu: m];
        startTimer (1);
    }
}

I suspect it has something to do with changes here.
This is the 5.2.1 version of menuNeedsUpdate in juice_macMainMenu.mm :

 static void menuNeedsUpdate (id self, SEL, NSMenu* menu)
        {
            getIvar<JuceMainMenuHandler*> (self, "owner")->updateTopLevelMenu (menu);
        }

here is the 4.xx version :

    static void menuNeedsUpdate (id, SEL, NSMenu* menu)
    {
        if (instance != nullptr)
            instance->updateMenus (menu);
    }

OK this is fixed on develop with commit 5b0b974. Thanks for reporting.

1 Like

The fix works.

Many thanks.

a wee thing I just noficed - in AudioPluginInstance there seems to be a void function attempting to return a value. Admittedly this is deprecated but am I missing something ?

void AudioPluginInstance::setParameter (int parameterIndex, float newValue)
{
assertOnceOnDeprecatedMethodUse();

if (auto* param = getParameters()[parameterIndex])
    return param->setValue (newValue);

}

I’ll sort this out. Thanks for reporting.