Verify not only that we don't destroy the window having the capture now but
also that this window is not in the mouse capture stack at all, not
necessarily on top. This is important as keeping a dangling pointer in the
capture stack would result in difficult to diagnose bugs later.
Also check that we don't recapture the mouse in the same window as this should
never be necessary.
Finally, give more details in the assert checking that the window does have
capture in ReleaseMouse().
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74677
c3d73ce0-8a6f-49c7-b76d-
6d57e0e08775
extern WXDLLEXPORT_DATA(const char) wxPanelNameStr[] = "panel";
extern WXDLLEXPORT_DATA(const char) wxPanelNameStr[] = "panel";
+namespace wxMouseCapture
+{
+
+// Check if the given window is in the capture stack.
+bool IsInCaptureStack(wxWindowBase* win);
+
+} // wxMouseCapture
+
// ----------------------------------------------------------------------------
// static data
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// static data
// ----------------------------------------------------------------------------
// common clean up
wxWindowBase::~wxWindowBase()
{
// common clean up
wxWindowBase::~wxWindowBase()
{
- wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") );
+ wxASSERT_MSG( !wxMouseCapture::IsInCaptureStack(this),
+ "Destroying window before releasing mouse capture: this "
+ "will result in a crash later." );
// FIXME if these 2 cases result from programming errors in the user code
// we should probably assert here instead of silently fixing them
// FIXME if these 2 cases result from programming errors in the user code
// we should probably assert here instead of silently fixing them
// Flag preventing reentrancy in {Capture,Release}Mouse().
wxRecursionGuardFlag changing;
// Flag preventing reentrancy in {Capture,Release}Mouse().
wxRecursionGuardFlag changing;
+bool IsInCaptureStack(wxWindowBase* win)
+{
+ for ( wxVector<wxWindow*>::const_iterator it = stack.begin();
+ it != stack.end();
+ ++it )
+ {
+ if ( *it == win )
+ return true;
+ }
+
+ return false;
+}
+
} // wxMouseCapture
void wxWindowBase::CaptureMouse()
} // wxMouseCapture
void wxWindowBase::CaptureMouse()
wxRecursionGuard guard(wxMouseCapture::changing);
wxASSERT_MSG( !guard.IsInside(), wxT("recursive CaptureMouse call?") );
wxRecursionGuard guard(wxMouseCapture::changing);
wxASSERT_MSG( !guard.IsInside(), wxT("recursive CaptureMouse call?") );
+ wxASSERT_MSG( !wxMouseCapture::IsInCaptureStack(this),
+ "Recapturing the mouse in the same window?" );
+
wxWindow *winOld = GetCapture();
if ( winOld )
((wxWindowBase*) winOld)->DoReleaseMouse();
wxWindow *winOld = GetCapture();
if ( winOld )
((wxWindowBase*) winOld)->DoReleaseMouse();
wxRecursionGuard guard(wxMouseCapture::changing);
wxASSERT_MSG( !guard.IsInside(), wxT("recursive ReleaseMouse call?") );
wxRecursionGuard guard(wxMouseCapture::changing);
wxASSERT_MSG( !guard.IsInside(), wxT("recursive ReleaseMouse call?") );
- wxASSERT_MSG( GetCapture() == this,
- "attempt to release mouse, but this window hasn't captured it" );
+#if wxDEBUG_LEVEL
+ wxWindow* const winCapture = GetCapture();
+ if ( !winCapture )
+ {
+ wxFAIL_MSG
+ (
+ wxString::Format
+ (
+ "Releasing mouse in %p(%s) but it is not captured",
+ this, GetClassInfo()->GetClassName()
+ )
+ );
+ }
+ else if ( winCapture != this )
+ {
+ wxFAIL_MSG
+ (
+ wxString::Format
+ (
+ "Releasing mouse in %p(%s) but it is captured by %p(%s)",
+ this, GetClassInfo()->GetClassName(),
+ winCapture, winCapture->GetClassInfo()->GetClassName()
+ )
+ );
+ }
+#endif // wxDEBUG_LEVEL
}
wxLogTrace(wxT("mousecapture"),
}
wxLogTrace(wxT("mousecapture"),
- (const wxChar *) wxT("After ReleaseMouse() mouse is captured by %p"),
+ wxT("After ReleaseMouse() mouse is captured by %p"),
static_cast<void*>(GetCapture()));
}
static_cast<void*>(GetCapture()));
}