X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/ae1cdb2d075b89badb7e429cde5f331ccbff2aef..3e33568e0bd8416417916d194fc9a50cab9636bf:/src/common/wincmn.cpp diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index 74c8056983..ad4887093b 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -72,6 +72,7 @@ #endif #include "wx/platinfo.h" +#include "wx/recguard.h" #include "wx/private/window.h" #ifdef __WINDOWS__ @@ -88,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 // ---------------------------------------------------------------------------- @@ -447,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 @@ -1102,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 @@ -1823,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 ); } @@ -1839,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); } @@ -3206,18 +3234,29 @@ 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; +// 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; -// the window that currently has mouse capture -wxWindow *current = NULL; +// 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; + } -// indicates if execution is inside CaptureMouse/ReleaseMouse -bool changing = false; + return false; +} } // wxMouseCapture @@ -3225,60 +3264,72 @@ void wxWindowBase::CaptureMouse() { wxLogTrace(wxT("mousecapture"), wxT("CaptureMouse(%p)"), static_cast(this)); - wxASSERT_MSG( !wxMouseCapture::changing, wxT("recursive CaptureMouse call?") ); + wxRecursionGuard guard(wxMouseCapture::changing); + wxASSERT_MSG( !guard.IsInside(), wxT("recursive CaptureMouse call?") ); - wxMouseCapture::changing = true; + 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::changing = false; + wxMouseCapture::stack.push_back(static_cast(this)); } void wxWindowBase::ReleaseMouse() { wxLogTrace(wxT("mousecapture"), wxT("ReleaseMouse(%p)"), static_cast(this)); - wxASSERT_MSG( !wxMouseCapture::changing, 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" ); + wxRecursionGuard guard(wxMouseCapture::changing); + wxASSERT_MSG( !guard.IsInside(), wxT("recursive ReleaseMouse call?") ); - wxMouseCapture::changing = true; +#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; - } - //else: stack is empty, no previous capture + wxMouseCapture::stack.pop_back(); - wxMouseCapture::changing = false; + // Restore the capture to the previous window, if any. + if ( !wxMouseCapture::stack.empty() ) + { + ((wxWindowBase*)wxMouseCapture::stack.back())->DoCaptureMouse(); + } wxLogTrace(wxT("mousecapture"), - (const wxChar *) wxT("After ReleaseMouse() mouse is captured by %p"), + wxT("After ReleaseMouse() mouse is captured by %p"), static_cast(GetCapture())); } @@ -3301,26 +3352,17 @@ void wxWindowBase::NotifyCaptureLost() { // don't do anything if capture lost was expected, i.e. resulted from // a wx call to ReleaseMouse or CaptureMouse: - if ( wxMouseCapture::changing ) + wxRecursionGuard guard(wxMouseCapture::changing); + if ( guard.IsInside() ) return; // 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(); } }