X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b0ad1918b955df68f2a38dc6720b91a49844a10d..534f87c6c442aa2710a44352bd26d215fec1714b:/src/common/wincmn.cpp?ds=sidebyside diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index b3479ab8d0..ad4887093b 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -89,6 +89,14 @@ wxMenu *wxCurrentPopupMenu = NULL; 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 // ---------------------------------------------------------------------------- @@ -448,7 +456,9 @@ bool wxWindowBase::ToggleWindowStyle(int flag) // 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 @@ -1103,6 +1113,12 @@ void wxWindowBase::SendSizeEventToParent(int flags) parent->SendSizeEvent(flags); } +bool wxWindowBase::CanScroll(int orient) const +{ + return (m_windowStyle & + (orient == wxHORIZONTAL ? wxHSCROLL : wxVSCROLL)) != 0; +} + bool wxWindowBase::HasScrollbar(int orient) const { // if scrolling in the given direction is disabled, we can't have the @@ -1824,6 +1840,12 @@ wxWindow *wxWindowBase::FindWindow(long id) const for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) { wxWindowBase *child = node->GetData(); + + // As usual, don't recurse into child dialogs, finding a button in a + // child dialog when looking in this window would be unexpected. + if ( child->IsTopLevel() ) + continue; + res = child->FindWindow( id ); } @@ -1840,6 +1862,11 @@ wxWindow *wxWindowBase::FindWindow(const wxString& name) const for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) { wxWindow *child = node->GetData(); + + // As in FindWindow() overload above, never recurse into child dialogs. + if ( child->IsTopLevel() ) + continue; + res = child->FindWindow(name); } @@ -3207,19 +3234,30 @@ wxHitTest wxWindowBase::DoHitTest(wxCoord x, wxCoord y) const namespace wxMouseCapture { -// the stack of windows which have captured the mouse -struct WindowNext -{ - wxWindow *win; - WindowNext *next; -} *next = NULL; - -// the window that currently has mouse capture -wxWindow *current = NULL; +// Stack of the windows which previously had the capture, the top most element +// is the window that has the mouse capture now. +// +// NB: We use wxVector and not wxStack to be able to examine all of the stack +// elements for debug checks, but only the stack operations should be +// performed with this vector. +wxVector stack; // Flag preventing reentrancy in {Capture,Release}Mouse(). wxRecursionGuardFlag changing; +bool IsInCaptureStack(wxWindowBase* win) +{ + for ( wxVector::const_iterator it = stack.begin(); + it != stack.end(); + ++it ) + { + if ( *it == win ) + return true; + } + + return false; +} + } // wxMouseCapture void wxWindowBase::CaptureMouse() @@ -3229,21 +3267,16 @@ void wxWindowBase::CaptureMouse() 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(); - // save it on stack - wxMouseCapture::WindowNext *item = new wxMouseCapture::WindowNext; - item->win = winOld; - item->next = wxMouseCapture::next; - wxMouseCapture::next = item; - } - //else: no mouse capture to save - DoCaptureMouse(); - wxMouseCapture::current = (wxWindow*)this; + + wxMouseCapture::stack.push_back(static_cast(this)); } void wxWindowBase::ReleaseMouse() @@ -3253,27 +3286,50 @@ void wxWindowBase::ReleaseMouse() 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" ); - wxASSERT_MSG( wxMouseCapture::current == 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 DoReleaseMouse(); - wxMouseCapture::current = NULL; - if ( wxMouseCapture::next ) - { - ((wxWindowBase*)wxMouseCapture::next->win)->DoCaptureMouse(); - wxMouseCapture::current = wxMouseCapture::next->win; + wxCHECK_RET( !wxMouseCapture::stack.empty(), + "Releasing mouse capture but capture stack empty?" ); + wxCHECK_RET( wxMouseCapture::stack.back() == this, + "Window releasing mouse capture not top of capture stack?" ); - wxMouseCapture::WindowNext *item = wxMouseCapture::next; - wxMouseCapture::next = item->next; - delete item; + wxMouseCapture::stack.pop_back(); + + // Restore the capture to the previous window, if any. + if ( !wxMouseCapture::stack.empty() ) + { + ((wxWindowBase*)wxMouseCapture::stack.back())->DoCaptureMouse(); } - //else: stack is empty, no previous capture wxLogTrace(wxT("mousecapture"), - (const wxChar *) wxT("After ReleaseMouse() mouse is captured by %p"), + wxT("After ReleaseMouse() mouse is captured by %p"), static_cast(GetCapture())); } @@ -3302,21 +3358,11 @@ void wxWindowBase::NotifyCaptureLost() // if the capture was lost unexpectedly, notify every window that has // capture (on stack or current) about it and clear the stack: - - if ( wxMouseCapture::current ) + while ( !wxMouseCapture::stack.empty() ) { - DoNotifyWindowAboutCaptureLost(wxMouseCapture::current); - wxMouseCapture::current = NULL; - } - - while ( wxMouseCapture::next ) - { - wxMouseCapture::WindowNext *item = wxMouseCapture::next; - wxMouseCapture::next = item->next; - - DoNotifyWindowAboutCaptureLost(item->win); + DoNotifyWindowAboutCaptureLost(wxMouseCapture::stack.back()); - delete item; + wxMouseCapture::stack.pop_back(); } }