Deleting or closing a DocumentWindow from within closeButtonPressed()


#1

I have a window that inherits from DocumentWindow. How do I indicate to JUCE that it can go ahead and close a window from within the method closeButtonPressed()?

When I look at the call stack at that point, I’m where you’d expect in the usual JUCE message handling. The stack looks like this:

MyWnd::closeButtonPressed()
juce::DocumentWindow::userTriedToCloseWindow()
juce::ComponentPeer::handleUserClosingWindow()
juce::LinuxComponentPeer::handleClientMessageEvent(XClientMessageEvent&, _XEvent&)
juce::LinuxComponentPeer::handleWindowMessage(_XEvent&)
...
juce::InternalMessageQueue::dispatchNextEvent()
juce::MessageManager::dispatchNextMessageOnSystemQueue(bool)
juce::MessageManager::runDispatchLoop()

If I call something like delete this (which is what the docs hint is one possibility) wont this cause serious memory problems when the object+method that is running all of a sudden is deleted before the method has finished returning?

Please excuse my English. Let me try and word it differently:

  1. MyWnd::closeButtonPressed() is running.
  2. Within that method, I call delete this
  3. Memory is reclaimed by the OS (or the C++ runtime) when the window is deleted
  4. …but MyWnd.closeButtonPressed() hasn’t returned yet! Wouldn’t it now be undefined behaviour since the memory area for MyWnd was released?

#2

Here’s one way to do it if you need your main window to reclaim whatever was inside your other window, say for popping out GUI components into their own detached window, and then reattaching them to the main window when you don’t want them to be floating…

void SeparateWindowModule::closeWindow()
{
    //assume that the SeparateModuleWindow instance has the pianoRollWindowContents as a child.
    owner.closeModuleWindow(this);
}
////////////
void ChordieMCC::closeModuleWindow(SeparateWindowModule *window)
{
    if( window == nullptr )
        return;
    if( window == pianoRollWindow )
    {
        pianoRollWindow = nullptr;
        addAndMakeVisible(pianoRollWindowContents); //re-add to our main window
    }
}

ScopedPointer<SeparateWindowModule> pianoRollWindow;
Component pianoRollWindowContents;

#3

Most of the code in the Component classes has extra safety checks when it makes to calls to user callbacks. So usually after returning from calling something like that, you’ll see a Component::BailOutChecker, SafePointer, WeakReference etc that detects whether it has been deleted and bails out safely. So yes, you’re pretty safe to delete this in most messaging callbacks, as long as that’s the last thing you do before returning!