Show PopupMenu on FileDragAndDropTarget::filesDropped()

When a user drops a file on my application, I'd like to give them some options as to what to do with it. I use a PopupMenu for this.

Because OSX gives your window focus only when you hover over it for, say, half a second, it can happen people drop a file without the window having focus. This creates all sorts of problems with the PopupMenu that's created on filesDropped().

  • The PopupMenu gets destroyed as soon as you mouse-exit it
  • I believe the popup gets destroyed as soon as the window does gain focus (using e.g. cmd+tab)

What's the best way to solve this? Can I force my window to take focus after dropping a file? Should I not use PopupMenu? Is this simply a restriction from OSX and can't it be helped?

(getTopLevelComponent()->toFront(true); doesn't work, but I've never done this and the documentation of DocumentWindow is rather...lacking, in this respect).

Does Process::makeForegroundProcess() do the trick?

Unfortunately, it doesn't :(

Then it may just be the OS preventing the app from coming to the front.

Yes, I was afraid of that. Nothing JUCE can't help, I guess. Thanks for clearing this up!

@jules can we revisit this once again? It’s a still occurring problem and I’m suspecting the OS isn’t actually at fault here.

What happens when I drop a file, show a pop-up and it immediately gets disposed (which it not always does), seems to be the following:

  1. show() makes the MenuWindow modal and runs the modal loop on it, which eventually calls MessageManager::runDispatchLoopUntil();
  2. This handles an event which calls canBecomeKeyWindow() of the JuceNSWindowClass of the underlying original window;
  3. Resulting in a NSViewComponentPeer::sendModalInputAttemptIfBlocked() call, which looks up the current modal component (The MenuWindow), calls inputAttemptWhenModal() resulting in a dismissMenu().

So, from what I understand (presumably very little): the menu is made modal, then the dispatch loop is ran with an event intended for the underlying Window still in there. Upon handling of that event the window tries to gain keyboard focus, which immediately dismisses the menu.

When the menu doesn’t immediately get dismissed, I also don’t get in sendModalInputAttemptIfBlocked(), which leads me to believe there is no event in the dispatch loop that could call canBecomeKeyWindow`.

I’m not very well known with the component peer code in JUCE, but to me this doesn’t seem like the OS is preventing the app from coming to the front, but rather the event pump not being emptied before the new menu window is created. Does that make sense? Is this something the JUCE codebase could handle differently? Or am I simply mistaken?


EDIT: Found another clue, which is that scheduling the menu.show() to happen at a slightly later timepoint seems to “fix” the issue as well:

juce::Process::makeForegroundProcess();
juce::Timer::callAfterDelay(100, [menu]() mutable { menu.show(); });