Make deleting toolbar from its own event handler work again
While it is not guaranteed in general that destroying a window from an
event handler for an event originating from this window itself works, it
did use to work in the case of wxToolBar and its event handlers. However
this stopped working since faffaaae29
as
it added a test using the now deleted object member fields after the
call to the event handler.
To fix this regression without reintroducing the bug fixed by that
commit (see #16762), add an ugly way to check if the toolbar is still
alive after a call to its event handler and do it explicitly after
OnLeftClick() returns.
Closes #17732.
This commit is contained in:
@@ -125,6 +125,14 @@ wxBEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
|
||||
EVT_ERASE_BACKGROUND(wxToolBar::OnEraseBackground)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// module globals
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// This is used to check if the toolbar itself doesn't get destroyed while
|
||||
// handling its event.
|
||||
static wxToolBar* gs_liveToolbar = NULL;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// private classes
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -505,6 +513,10 @@ void wxToolBar::Recreate()
|
||||
|
||||
wxToolBar::~wxToolBar()
|
||||
{
|
||||
// Indicate to the code in MSWCommand() that the toolbar is destroyed.
|
||||
if ( gs_liveToolbar == this )
|
||||
gs_liveToolbar = NULL;
|
||||
|
||||
// we must refresh the frame size when the toolbar is deleted but the frame
|
||||
// is not - otherwise toolbar leaves a hole in the place it used to occupy
|
||||
SendSizeEventToParent();
|
||||
@@ -1455,8 +1467,23 @@ bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id_)
|
||||
::SendMessage(GetHwnd(), TB_SETSTATE, id, MAKELONG(state | TBSTATE_PRESSED, 0));
|
||||
Update();
|
||||
|
||||
// Before calling the event handler, store a pointer to this toolbar in the
|
||||
// global variable: if it gets reset from our dtor, we will know that the
|
||||
// toolbar was destroyed by this handler and that we can't use this object
|
||||
// any more.
|
||||
gs_liveToolbar = this;
|
||||
|
||||
bool allowLeftClick = OnLeftClick(id, toggled);
|
||||
|
||||
if ( gs_liveToolbar != this )
|
||||
{
|
||||
// Bail out, we can't touch any member fields in the already
|
||||
// destroyed object anyhow.
|
||||
return true;
|
||||
}
|
||||
|
||||
gs_liveToolbar = NULL;
|
||||
|
||||
// Check if the tool hasn't been deleted in the event handler (notice that
|
||||
// it's also possible that this tool was deleted and a new tool with the
|
||||
// same ID was created, so we really need to check if the pointer to the
|
||||
|
Reference in New Issue
Block a user