From 601398b9b1e63109f44af34ff79bc558fe929b4d Mon Sep 17 00:00:00 2001 From: Bryan Petty Date: Tue, 22 Jan 2008 08:20:18 +0000 Subject: [PATCH] Fixed a rare wxAuiFloatingFrame dtor crash on MSW using a registration mechanism in wxAuiManager. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51324 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/aui/floatpane.h | 3 +++ include/wx/aui/framemanager.h | 13 +++++++--- src/aui/floatpane.cpp | 44 +++++++++++++++++++++++++-------- src/aui/framemanager.cpp | 46 ++++++++++++++++++++++++++++++++++- 4 files changed, 92 insertions(+), 14 deletions(-) diff --git a/include/wx/aui/floatpane.h b/include/wx/aui/floatpane.h index 837a9d789e..8c73605676 100644 --- a/include/wx/aui/floatpane.h +++ b/include/wx/aui/floatpane.h @@ -31,6 +31,8 @@ class WXDLLIMPEXP_AUI wxAuiFloatingFrame : public wxAuiFloatingFrameBaseClass { + friend class wxAuiManager; + public: wxAuiFloatingFrame(wxWindow* parent, wxAuiManager* owner_mgr, @@ -45,6 +47,7 @@ public: wxAuiManager* GetOwnerManager() const; protected: + void SetOwnerManager(wxAuiManager* owner_mgr); virtual void OnMoveStart(); virtual void OnMoving(const wxRect& window_rect, wxDirection dir); virtual void OnMoveFinished(); diff --git a/include/wx/aui/framemanager.h b/include/wx/aui/framemanager.h index 77a7d8b1d6..4043147af0 100644 --- a/include/wx/aui/framemanager.h +++ b/include/wx/aui/framemanager.h @@ -121,6 +121,7 @@ enum wxAuiPaneInsertLevel // forwards and array declarations +class WXDLLIMPEXP_FWD_AUI wxAuiFloatingFrame; class wxAuiDockUIPart; class wxAuiPaneButton; class wxAuiPaneInfo; @@ -133,6 +134,7 @@ WX_DECLARE_USER_EXPORTED_OBJARRAY(wxAuiDockInfo, wxAuiDockInfoArray, WXDLLIMPEXP WX_DECLARE_USER_EXPORTED_OBJARRAY(wxAuiDockUIPart, wxAuiDockUIPartArray, WXDLLIMPEXP_AUI); WX_DECLARE_USER_EXPORTED_OBJARRAY(wxAuiPaneButton, wxAuiPaneButtonArray, WXDLLIMPEXP_AUI); WX_DECLARE_USER_EXPORTED_OBJARRAY(wxAuiPaneInfo, wxAuiPaneInfoArray, WXDLLIMPEXP_AUI); +WX_DEFINE_USER_EXPORTED_ARRAY_PTR(wxAuiFloatingFrame*, wxAuiFloatingFramePtrArray, class WXDLLIMPEXP_AUI); WX_DEFINE_USER_EXPORTED_ARRAY_PTR(wxAuiPaneInfo*, wxAuiPaneInfoPtrArray, class WXDLLIMPEXP_AUI); WX_DEFINE_USER_EXPORTED_ARRAY_PTR(wxAuiDockInfo*, wxAuiDockInfoPtrArray, class WXDLLIMPEXP_AUI); #endif // SWIG @@ -419,11 +421,9 @@ public: -class WXDLLIMPEXP_FWD_AUI wxAuiFloatingFrame; - class WXDLLIMPEXP_AUI wxAuiManager : public wxEvtHandler { -friend class wxAuiFloatingFrame; + friend class wxAuiFloatingFrame; public: @@ -511,6 +511,12 @@ public: protected: + // Sometimes floating frames are deleted after wxAuiManager, so we need + // to clear m_owner_mgr in the floating frame to avoid a crash. To do so, + // we register frames with wxAuiManager so it can keep track. + void RegisterFloatingFrame(wxAuiFloatingFrame* frame); + void UnregisterFloatingFrame(wxAuiFloatingFrame* frame); + void UpdateHintWindowConfig(); void DoFrameLayout(); @@ -601,6 +607,7 @@ protected: wxAuiPaneInfoArray m_panes; // array of panes structures wxAuiDockInfoArray m_docks; // array of docks structures wxAuiDockUIPartArray m_uiparts; // array of UI parts (captions, buttons, etc) + wxAuiFloatingFramePtrArray m_floating_frames; // array of floating frames int m_action; // current mouse action wxPoint m_action_start; // position where the action click started diff --git a/src/aui/floatpane.cpp b/src/aui/floatpane.cpp index 1a7357f824..ab81810d61 100644 --- a/src/aui/floatpane.cpp +++ b/src/aui/floatpane.cpp @@ -73,10 +73,13 @@ wxAuiFloatingFrame::wxAuiFloatingFrame(wxWindow* parent, wxAuiFloatingFrame::~wxAuiFloatingFrame() { // if we do not do this, then we can crash... - if(m_owner_mgr && m_owner_mgr->m_action_window == this) + if(m_owner_mgr) { - m_owner_mgr->m_action_window = NULL; + if(m_owner_mgr->m_action_window == this) + m_owner_mgr->m_action_window = NULL; + m_owner_mgr->UnregisterFloatingFrame(this); } + m_mgr.UnInit(); } @@ -133,7 +136,7 @@ void wxAuiFloatingFrame::SetPaneWindow(const wxAuiPaneInfo& pane) size = pane.min_size; if (size == wxDefaultSize) size = m_pane_window->GetSize(); - if (pane.HasGripper()) + if (m_owner_mgr && pane.HasGripper()) { if (pane.HasGripperTop()) size.y += m_owner_mgr->m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE); @@ -150,16 +153,28 @@ wxAuiManager* wxAuiFloatingFrame::GetOwnerManager() const return m_owner_mgr; } +void wxAuiFloatingFrame::SetOwnerManager(wxAuiManager* owner_mgr) +{ + // we want to allow for NULL here to avoid crashing in dtor + m_owner_mgr = owner_mgr; +} void wxAuiFloatingFrame::OnSize(wxSizeEvent& event) { - m_owner_mgr->OnFloatingPaneResized(m_pane_window, event.GetSize()); + if (m_owner_mgr) + { + m_owner_mgr->OnFloatingPaneResized(m_pane_window, event.GetSize()); + } } void wxAuiFloatingFrame::OnClose(wxCloseEvent& evt) { - m_owner_mgr->OnFloatingPaneClosed(m_pane_window, evt); - if (!evt.GetVeto()) { + if (m_owner_mgr) + { + m_owner_mgr->OnFloatingPaneClosed(m_pane_window, evt); + } + if (!evt.GetVeto()) + { m_mgr.DetachPane(m_pane_window); Destroy(); } @@ -271,25 +286,34 @@ void wxAuiFloatingFrame::OnIdle(wxIdleEvent& event) void wxAuiFloatingFrame::OnMoveStart() { // notify the owner manager that the pane has started to move - m_owner_mgr->OnFloatingPaneMoveStart(m_pane_window); + if (m_owner_mgr) + { + m_owner_mgr->OnFloatingPaneMoveStart(m_pane_window); + } } void wxAuiFloatingFrame::OnMoving(const wxRect& WXUNUSED(window_rect), wxDirection dir) { // notify the owner manager that the pane is moving - m_owner_mgr->OnFloatingPaneMoving(m_pane_window, dir); + if (m_owner_mgr) + { + m_owner_mgr->OnFloatingPaneMoving(m_pane_window, dir); + } m_lastDirection = dir; } void wxAuiFloatingFrame::OnMoveFinished() { // notify the owner manager that the pane has finished moving - m_owner_mgr->OnFloatingPaneMoved(m_pane_window, m_lastDirection); + if (m_owner_mgr) + { + m_owner_mgr->OnFloatingPaneMoved(m_pane_window, m_lastDirection); + } } void wxAuiFloatingFrame::OnActivate(wxActivateEvent& event) { - if (event.GetActive()) + if (m_owner_mgr && event.GetActive()) { m_owner_mgr->OnFloatingPaneActivated(m_pane_window); } diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index c94279ccd6..4c856f2c52 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -610,6 +610,17 @@ wxAuiManager::~wxAuiManager() } #endif + // We need to remove any reference to this wxAuiManager in any of the + // wxAuiFloatingFrames associated with this manager in case they haven't + // been deleted just yet. + // We need an array copy since Unregister removes the items. + wxAuiFloatingFramePtrArray array_copy = m_floating_frames; + int i, count = array_copy.GetCount(); + for (i = 0; i < count; ++i) + { + UnregisterFloatingFrame(array_copy.Item(i)); + } + delete m_art; } @@ -617,7 +628,9 @@ wxAuiManager::~wxAuiManager() wxAuiFloatingFrame* wxAuiManager::CreateFloatingFrame(wxWindow* parent, const wxAuiPaneInfo& pane_info) { - return new wxAuiFloatingFrame(parent, this, pane_info); + wxAuiFloatingFrame* frame = new wxAuiFloatingFrame(parent, this, pane_info); + RegisterFloatingFrame(frame); + return frame; } bool wxAuiManager::CanDockPanel(const wxAuiPaneInfo & WXUNUSED(p)) @@ -627,6 +640,37 @@ bool wxAuiManager::CanDockPanel(const wxAuiPaneInfo & WXUNUSED(p)) return !(wxGetKeyState(WXK_CONTROL) || wxGetKeyState(WXK_ALT)); } +// registers a floating frame with this manager (see header) +void wxAuiManager::RegisterFloatingFrame(wxAuiFloatingFrame* frame) +{ + frame->SetOwnerManager(this); + int i, count = m_floating_frames.GetCount(); + for (i = 0; i < count; ++i) + { + wxAuiFloatingFrame* f = m_floating_frames.Item(i); + if (f == frame) + // this frame is already registered + return; + } + m_floating_frames.Add(frame); +} + +// unregisters a floating frame from this manager (see header) +void wxAuiManager::UnregisterFloatingFrame(wxAuiFloatingFrame* frame) +{ + frame->SetOwnerManager(NULL); + int i, count = m_floating_frames.GetCount(); + for (i = 0; i < count; ++i) + { + wxAuiFloatingFrame* f = m_floating_frames.Item(i); + if (f == frame) + { + m_floating_frames.Remove(f); + return; + } + } +} + // GetPane() looks up a wxAuiPaneInfo structure based // on the supplied window pointer. Upon failure, GetPane() // returns an empty wxAuiPaneInfo, a condition which can be checked