MenuBar in plugin hosts


#1

Im having a very weird problem with the MenuBar in Cubase and Ableton live (In reaper it works ok and in logic on mac its fine too) i must admit i have tested on cubase and live only on pc.
When a user clicks on a menu item in the MenuBar it flashes quickly and closes. if the user drags his mouse the menu item appears again and the menubar is usable.
Its possible to see that the plugin window is loosing and regaining focus when the menu flashes, and then loosing focus again when the menu is draged and working.
This happens every time a user wants to use the menu not just the first time.
Ableton also does not get key strokes.

I have put

setAlwaysOnTop(true); setWantsKeyboardFocus(true); setMouseClickGrabsKeyboardFocus(true); grabKeyboardFocus();
on both the plugin editor and the menubarcomponent, but to no avail.
any ideas on what i may be doing wrong?
the funny thing is that the software receives focus once i drag the mouse over the menubar, but i cannot even enter next on the texteditors.


#2

small update:
cubase gets key stroaks except for some like the delete or backspace key, but the menus behave the same
here is a short screen capture of the bug:
http://gogma.com/menu.html

there is some focus funky going on in there


#3

I’ve done some debugging and i tracked focus gain and loss on some windows VST hosts.

When i click on the menu (or any other component but the menu is affected by the situation more drastically)
EditorCompWrapper calls BroughtToFront() which calles SetWindowPos, in the VST wrapper.
on some hosts this does not result in the window loosing focus (like SaviHost or Reaper for instance) but on Cubase and Live, this call ends up at
peerWindowProc case WM_KILLFOCUS which kills the focus of the window, resulting in the popup menu closing prematurely.

Any ideas on possible workarounds or why this is happening ?


#4

Interesting stuff - thanks for doing some digging.

I guess that some hosts must be catching the event and using it to jiggle their windows around. Perhaps the wrapper code should just perform the SetWindowPos when you actually click the mouse, rather than whenever the window gets brought to the front, e.g.

[code] #if JUCE_WINDOWS
void mouseDown (const MouseEvent&)
{
// for hosts like nuendo, need to also pop the MDI container to the
// front when our comp is clicked on.
HWND parent = findMDIParentOf ((HWND) getWindowHandle());

        if (parent != 0)
            SetWindowPos (parent, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    }

    void broughtToFront()
    {
    }
   #endif

[/code]

…I’ve a suspicion that I must have put it in the broughtToFront() callback for a good reason, but can’t think why that might have been the case at the moment.


#5

Thanks for checking this jules!

perhaps I wasn’t clear,
Clicking the menus triggers mouseDown() on EditorCompWrapper which triggers broughtToFront() so even if i remove the code from broughtToFront and place it on mouseDown() i get the same behavior.
perhaps gaining focus should happen only if the plugin has no focus in the first place.

it is very tricky to handle focus if the host keeps taking it away a second after you requested it and then giving it back.


#6

Hmm. Not sure then… I guess the problem is just that the menu’s mouse event callback happens before this one. Maybe it could have a check to see if there’s another juce window in front of it, and not call SetWindowPos in that case…?


#7

If i comment out that whole part of code it works ok.
however im not sure i understand what it needs to do
you wrote:

// for hosts like nuendo, need to also pop the MDI container to the // front when our comp is clicked on.
What is an MDI container and what are the consequences of it not poping to the front?
If it is the plugin container, for cubase and live it pops to the front without this call. i haven’t checked out nuendo yet, but isn’t nuendo the same as cubase in this case? perhaps this is relevant to older versions? maybe this should be conditioned by the host type and only enable it for hosts which need this function?
what do you think?


#8

It’s needed because if the plugin window is behind another one and you click on it, it needs to bring the window to the front. It could be enabled for only some hosts, but that wouldn’t fix your problem.

Does it help if you add the SWP_NOSENDCHANGING flag, like this?

SetWindowPos (parent, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOSENDCHANGING);


#9

No, it doesn’t help adding SWP_NOSENDCHANGING

if it is enabled just to the problematic hosts it could reduce the problem to a minimum or maybe even eliminate it, because it may very well be that the hosts that need this call dont take away the focus after it.
Cubase and live are fine with it gone, there is no problem bringing the plugin to the front, so perhaps i should try removing it for my next alpha and see which users have an issue with bringing the plugin to front. and this way we can narrow this bug to occurring in the less popular hosts. another approach is just disable the call for specific hosts that exhibit the menu problem.

is there any way to check if the plugin has focus already? i tried

but it looks wierd and doesnt work.


#10

It’s unlikely a user would report that the window doesn’t pop to the front, they’d more likely just find it a bit annoying and click the title bar to get it.

The “correct” way to fix it would be to hack things around so that broughtToFront is always called before the click event gets passed to the component that pops up the menu, so that it’d already be on top when that happens. Not sure of the best way to do that though…?


#11

Ok i think i may have climbed the wrong tree here.
the SetWindowPos() function does not always result in focus loss.
infact, right click menus work just fine and clickable text editors don’t loose focus.

This happens when triggering showMenuAsync() in the popupMenu.
I tried converting one of my right click popupMenus from show() to showMenuAsync() and got the same behavior.

This still has to do something with SetWindowPos() as without it the showMenuAsync() works.

Im not so sure now that it has to do with the mouseDown listener being called later, because the bug would be manifesting itself in many more places.