#endif
#include "wx/platinfo.h"
+#include "wx/recguard.h"
#include "wx/private/window.h"
#ifdef __WINDOWS__
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
// ----------------------------------------------------------------------------
// 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
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
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 );
}
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);
}
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<wxWindow*> 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<wxWindow*>::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
{
wxLogTrace(wxT("mousecapture"), wxT("CaptureMouse(%p)"), static_cast<void*>(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<wxWindow*>(this));
}
void wxWindowBase::ReleaseMouse()
{
wxLogTrace(wxT("mousecapture"), wxT("ReleaseMouse(%p)"), static_cast<void*>(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<void*>(GetCapture()));
}
{
// 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();
}
}