getMenuForIndex called twice on focus change


#1

Hello,

It seems that when using the native osx menu bar, The MenuBarModel::getMenuForIndex function is called on every focus change. Well, it’s being called twice actually. The function will not get called when clicking on any of the menu’s, as happens when using the juce menu instead.

In the application I’m developing, there are a number of elements in a grid. Each element can have different settings, that should be reflected in the main menu. For reasons unclear to me, switching focus on these elements doesn’t cause the menu callback function to be called, resulting in a incorrectly filled-out menu.

I’m curious to know what actually causes the getMenuForIndex to be called. The version i’m using is the git version as of 14-05-2011. Any significant between then and the release?


#2

It’s called whenever anything loses or gains focus… If you can find a situation where it doesn’t work, please give me some example code so I can try it myself.


#3

Hmm… I presume this is because you don’t receive any callbacks when the user clicks on the menu, so you have to fill it pre-emtively?

The problematic code is rather complex and to tell the thruth, I don’t know how it works :slight_smile: I quess it’s due to something having the wrong order… Could you point me to where the code that initiates the menu update is?


#4

Okay I’ve tracked it to Component::grabFocusInternal… That seems pretty obvious. I should be able to get to the bottom of this.
BTW, the repeated calling of getMenuForIndex happens in the Juce Demo as well.


#5

There’s nothing inherently wrong with it getting called more than once… Why are you talking about that as if it’s a bug?


#6

No It’s not really a bug, I just meant to point out that the Demo exhibits this behaviour. I’m not stating that there is a bug, I’m just curious why the menu isn’t “filled” when it’s about to open.

If I have a look at the NSMenuDelegate documentation, it seems to me that menuNeedsUpdate: (NSMenu*) menu should be able to fill the menu just before it’s about to display it. Although it seems this is never called (running osx 10.6)…

The reason why I want to have the menu’s updated this ways is because of a strange threading / timing issue that stems from the stringing of asyncupdates. This eventually returns me the wrong object (the one that was selected previously). The code then proceeds to create a menu based on the wrong object.
If the menu were to be built prior to displaying it, I’m able to base it on the correct object.


#7

Okay, let me rephrase this.

When running a previous version of our app that compiles against the svn rev. 684 of Juce, the following code is called when clicking on a menu: (juce_mac_MainMenu.mm)

- (void) menuNeedsUpdate: (NSMenu*) menu; { if (JuceMainMenuHandler::instance != 0) JuceMainMenuHandler::instance->updateMenus(); }

The version of juce I having problems with (Git from 14-05-11) has the same code, but the difference is that it isn’t called. This breaks the menu update. Why isn’t this called any longer?


#8

It’s an OS callback - if it’s not getting called, then the OS isn’t calling it any more… Not sure why!


#9

I hope it was due to something like the base SDK or Development target, but I switched them both to 10.4 (as was in the build that worked), but the menuNeedsUpdate still isn’t called. It’s not a debug issue, because I can verify that menuItemInvoked is called.

The only seemingly meaningful differences between the two Mac_MainMenu.mm’s seem to be the not doing in place menu updating (some keyboard focus issue) and changing around some nulptrs.

Am I correct when I think that all communication between OSX and the menu goes through the MenuDelegate?


#10

Yes, I think so.


#11

After some researching i found that creating new submenus is to blame for the lack of updates.
When changing

[code]void updateSubMenu (NSMenuItem* parentItem, const PopupMenu& menuToCopy,
const String& name, const int menuId, const int tag)
{
// Note: This method used to update the contents of the existing menu in-place, but that caused
// weird side-effects which messed-up keyboard focus when switching between windows. By creating
// a new menu and replacing the old one with it, that problem seems to be avoided…
NSMenu* menu = [[NSMenu alloc] initWithTitle: juceStringToNS (name)];

    PopupMenu::MenuItemIterator iter (menuToCopy);
    while (iter.next())
        addMenuItem (iter, menu, menuId, tag);

    [menu setAutoenablesItems: false];
    [menu update];
    [parentItem setTag: tag];
    [parentItem setSubmenu: menu];
    [menu release];
}[/code]

into

[code] void updateSubMenu (NSMenuItem* parentItem, const PopupMenu& menuToCopy,
const String& name, const int menuId, const int tag)
{
[parentItem setTag: tag];
NSMenu* menu = [parentItem submenu];

    [menu setTitle: juceStringToNS (name)];

    while ([menu numberOfItems] > 0)
        [menu removeItemAtIndex: 0];

    PopupMenu::MenuItemIterator iter (menuToCopy);

    while (iter.next())
        addMenuItem (iter, menu, menuId, tag);

    [menu setAutoenablesItems: false];
    [menu update];
}[/code]

(that is: reverting the function back to rev 684), I get the updates from OSX again. In the newer code, it seems like you’re replacing the current menu with a new one. But, it seems you don’t set a delegate on this new menu. Regrettably, setting a delegate on the new menu (after [menu release]) doesn’t bring back updates…

edit oops you DO set the delegate… my bad.


#12

But if the delegate wasn’t working, then none of the menu items would actually work, because the delegate receives the callback when an item is selected…


#13

Yes, of course. But do you have any idea what could be the cause then?


#14

I don’t know, but I still don’t really understand what the problem is!

It sounds to me like an extra callback was being accidentally triggered by the old code, and your program was relying on that broken behaviour…?


#15

The problem is that the menu’s are now being updated upon focus change, whereas before they where being updated when you actually clicked on the menu, just before displaying it.

More specifically: a system callback isn’t being made anymore since you changed the offending code. As the newer code actually breaks a system callback mechanism, I would hardly say that my program relies on broken / accidental functionality.


#16

Ok, gotcha… but I really don’t know what to suggest! The change I made is essential, it can’t be removed without breaking things, I guess there’s something a bit screwy inside the Apple menu code. Too deep in other stuff to investigate right now, but keep nagging me!


#17

Good, I’ll keep nagging you in the future :slight_smile:

But for now: do you know exactly what it is that your new code has fixed? In the code it says something about keyboard focus… If we knew that, we could make a workaround that fixes this in another way while still keeping the old code that keeps the apple-menu-callback system alive.


#18

Well? Do you remember what it was?


#19

I think it was this one:
http://www.rawmaterialsoftware.com/viewtopic.php?f=2&t=7350&hilit=mac+menu


#20

If the behaviour described in the thread would cause a crash with the old code I would have no trouble reproducing this behaviour. But it doesn’t happen, so I guess it the new code fixes something else than you suggested.