DialogWindow appears behind plug-in window

Hi,

I had the DialogWindow created by showModalDialog appearing behind the plug-in window in Logic, but I noticed that AlertWindows did not suffer of this bug.

Digging into the code, I found that the following code does the trick for the AlertWindow:

if (JUCEApplication::getInstance() == 0)
        setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level

What about integrating the same code into DialogWindow (as proposed below)? Otherwise, adding an addToDesktop parameter to the funcion (defaulted to false) would work equally well without changing the behaviour of existing code, but I doubt that making a modal DialogWindow appear behind some other window is of any use at all…

(the proposed change requires the inclusion of “…/…/…/application/juce_Application.h” at the beginning of the DialogWindow.cpp)

[code]int DialogWindow::showModalDialog (const String& dialogTitle,
Component* contentComponent,
Component* componentToCentreAround,
const Colour& colour,
const bool escapeKeyTriggersCloseButton,
const bool shouldBeResizable,
const bool useBottomRightCornerResizer)
{
TempDialogWindow dw (dialogTitle, colour, escapeKeyTriggersCloseButton);

dw.setContentComponent (contentComponent, true, true);
dw.centreAroundComponent (componentToCentreAround, dw.getWidth(), dw.getHeight());
dw.setResizable (shouldBeResizable, useBottomRightCornerResizer);
if (JUCEApplication::getInstance() == 0)
    dw.setAlwaysOnTop (true); // for a plugin, make it always-on-top because the host windows are often top-level
const int result = dw.runModalLoop();
dw.setContentComponent (0, false);
return result;

}
[/code]

Sounds like a sensible request, thanks!

The same happens with the new CallOutBox class BTW

Good point, thanks!

And I don’t know if it’s me or not, I should try with the plugin demo, but if I close the plugin window when a CallOutBox is active then when closing the plugin there’s an assert in ~Desktop() and ~MessageManager() saying that there are leaked Components. It doesn’t happen otherwise.

Well, if you don’t clean up the modal component when your UI gets deleted, it’ll leak. Probably not a big deal, as the plugin’s getting unloaded at that point anyway, but personally, I’d suggest that when you create a callout box, you could keep a ScopedPointer to it in your UI class, so it’ll definitely get removed when the UI goes away.

It is allocated on the stack as in the example you have in the documentation.

void mouseDown(const MouseEvent &e)
{
    CallOutBox callOut(*mpColourSelector, *this, NULL);
    callOut.runModalLoop();
}

You really, really need to avoid runModalLoop() in a plugin. It’s ok in an app, but if the host chooses to delete your plugin during the runModalLoop() call, then when the method returns, your plugin has gone from memory and the stack unwinding will probably cause a crash.

Instead use Component::enterModalState(), and provide a callback if you need to know when it has finished.

Thanks for the info, does that mean that any modal dialog should be avoided including PopupMenu?

If possible, yes. PopupMenu::show() now has a callback parameter that lets you run it without a modal loop.

Ok thanks that works fine now with CallOutBox.

One more question

in showMenu there is a ScopedPointer to hold the userCallback but if there’s a userCallback the method returns immediately.

The userCallback should be deleted at this point no?

[code]
int PopupMenu::showMenu (const Rectangle& target,
const int itemIdThatMustBeVisible,
const int minimumWidth,
const int maximumNumColumns,
const int standardItemHeight,
const bool alignToRectangle,
Component* const componentAttachedTo,
ModalComponentManager::Callback* userCallback)
{
ScopedPointerModalComponentManager::Callback userCallbackDeleter (userCallback);

...

if (userCallback != 0)
    return 0;

const int result = callback->component->runModalLoop();[/code]

No, the ModalComponentManager takes care of deleting that callback object later on.

oh, I missed the use of release on ScopedPointer