From 2806b509e23ff154b67b93be6630ff2fe718896b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Mon, 26 Jun 2017 13:40:19 -0400 Subject: [PATCH] Fix crashes in repainting, and update first visible track correctly --- src/Project.cpp | 75 +++++++++++++++++++++------------------------- src/Project.h | 6 ++-- src/Track.cpp | 10 +++++++ src/Track.h | 4 +++ src/TrackPanel.cpp | 3 +- src/ViewInfo.cpp | 1 - src/ViewInfo.h | 3 +- 7 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/Project.cpp b/src/Project.cpp index fbde87380..6f97f7d23 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -944,8 +944,16 @@ AudacityProject::AudacityProject(wxWindow * parent, wxWindowID id, mLastSavedTracks = NULL; // Register for tracklist updates + mTracks->Connect(EVT_TRACKLIST_PERMUTED, + wxCommandEventHandler(AudacityProject::OnTrackListUpdate), + NULL, + this); mTracks->Connect(EVT_TRACKLIST_DELETION, - wxCommandEventHandler(AudacityProject::OnTrackListDeletion), + wxCommandEventHandler(AudacityProject::OnTrackListUpdate), + NULL, + this); + mTracks->Connect(EVT_TRACKLIST_RESIZING, + wxCommandEventHandler(AudacityProject::OnTrackListUpdate), NULL, this); @@ -1974,9 +1982,8 @@ void AudacityProject::FixScrollbars() rescroll = false; } - if (lastv != mViewInfo.vpos) { - UpdateFirstVisible(); - } + if (lastv != mViewInfo.vpos) + InvalidateFirstVisible(); // wxScrollbar only supports int values but we need a greater range, so // we scale the scrollbar coordinates on demand. We only do this if we @@ -2020,51 +2027,30 @@ void AudacityProject::FixScrollbars() } } -Track *AudacityProject::GetFirstVisible() +std::shared_ptr AudacityProject::GetFirstVisible() { - if (!mViewInfo.track && GetTracks()) { + auto pTrack = mViewInfo.track.lock(); + if (!pTrack && GetTracks()) { + // Recompute on demand and memo-ize TrackListIterator iter(GetTracks()); for (Track *t = iter.First(); t; t = iter.Next()) { int y = t->GetY(); int h = t->GetHeight(); if (y + h - 1 >= mViewInfo.vpos) { // At least the bottom row of pixels is not scrolled away above - mViewInfo.track = t; + pTrack = Track::Pointer(t); break; } } + mViewInfo.track = pTrack; } - return mViewInfo.track; + return pTrack; } -void AudacityProject::UpdateFirstVisible() +void AudacityProject::InvalidateFirstVisible() { - if (!mViewInfo.track || !GetTracks()) { - return; - } - - Track *t = mViewInfo.track; - mViewInfo.track = NULL; - - if (t->GetY() >= mViewInfo.vpos) { - while (t && t->GetY() >= mViewInfo.vpos) { - t = mTracks->GetPrev(t); - } - } - - while (t) { - int y = t->GetY(); - int h = t->GetHeight(); - if (y + h - 1 >= mViewInfo.vpos) { - // At least the bottom row of pixels is not scrolled away above - mViewInfo.track = t; - return; - } - t = mTracks->GetNext(t); - } - - return; + mViewInfo.track.reset(); } void AudacityProject::UpdateLayout() @@ -2222,9 +2208,9 @@ void AudacityProject::OnToolBarUpdate(wxCommandEvent & event) } // The projects tracklist has been updated -void AudacityProject::OnTrackListDeletion(wxCommandEvent & event) +void AudacityProject::OnTrackListUpdate(wxCommandEvent & event) { - mViewInfo.track = NULL; + InvalidateFirstVisible(); event.Skip(); } @@ -2275,9 +2261,8 @@ void AudacityProject::DoScroll() int lastv = mViewInfo.vpos; mViewInfo.vpos = mVsbar->GetThumbPosition() * mViewInfo.scrollStep; - if (lastv != mViewInfo.vpos) { - UpdateFirstVisible(); - } + if (lastv != mViewInfo.vpos) + InvalidateFirstVisible(); //mchinen: do not always set this project to be the active one. //a project may autoscroll while playing in the background @@ -2692,8 +2677,16 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) mImportXMLTagHandler.reset(); // Unregister for tracklist updates + mTracks->Disconnect(EVT_TRACKLIST_PERMUTED, + wxCommandEventHandler(AudacityProject::OnTrackListUpdate), + NULL, + this); mTracks->Disconnect(EVT_TRACKLIST_DELETION, - wxCommandEventHandler(AudacityProject::OnTrackListDeletion), + wxCommandEventHandler(AudacityProject::OnTrackListUpdate), + NULL, + this); + mTracks->Disconnect(EVT_TRACKLIST_RESIZING, + wxCommandEventHandler(AudacityProject::OnTrackListUpdate), NULL, this); @@ -3529,7 +3522,7 @@ bool AudacityProject::HandleXMLTag(const wxChar *tag, const wxChar **attrs) if (longVpos != 0) { // PRL: It seems this must happen after SetSnapTo - mViewInfo.track = NULL; + mViewInfo.track.reset(); mViewInfo.vpos = longVpos; mbInitializingScrollbar = true; } diff --git a/src/Project.h b/src/Project.h index f21b5fbc0..769c81128 100644 --- a/src/Project.h +++ b/src/Project.h @@ -191,8 +191,8 @@ class AUDACITY_DLL_API AudacityProject final : public wxFrame, const ViewInfo &GetViewInfo() const { return mViewInfo; } ViewInfo &GetViewInfo() { return mViewInfo; } - Track *GetFirstVisible(); - void UpdateFirstVisible(); + std::shared_ptr GetFirstVisible(); + void InvalidateFirstVisible(); void GetPlayRegion(double* playRegionStart, double *playRegionEnd); bool IsPlayRegionLocked() { return mLockPlayRegion; } @@ -355,7 +355,7 @@ public: void OnOpenAudioFile(wxCommandEvent & event); void OnODTaskUpdate(wxCommandEvent & event); void OnODTaskComplete(wxCommandEvent & event); - void OnTrackListDeletion(wxCommandEvent & event); + void OnTrackListUpdate(wxCommandEvent & event); void HandleResize(); void UpdateLayout(); diff --git a/src/Track.cpp b/src/Track.cpp index 2fcc6963a..3247a0a84 100644 --- a/src/Track.cpp +++ b/src/Track.cpp @@ -741,6 +741,7 @@ Track *SyncLockedTracksIterator::Last(bool skiplinked) // is managing. Any other classes that may be interested in get these updates // should use TrackList::Connect() and TrackList::Disconnect(). // +DEFINE_EVENT_TYPE(EVT_TRACKLIST_PERMUTED); DEFINE_EVENT_TYPE(EVT_TRACKLIST_RESIZING); DEFINE_EVENT_TYPE(EVT_TRACKLIST_DELETION); @@ -856,6 +857,13 @@ void TrackList::RecalcPositions(TrackNodePointer node) #endif // EXPERIMENTAL_OUTPUT_DISPLAY } +void TrackList::PermutationEvent() +{ + auto e = std::make_unique(EVT_TRACKLIST_PERMUTED); + // wxWidgets will own the event object + QueueEvent(e.release()); +} + void TrackList::DeletionEvent() { auto e = std::make_unique(EVT_TRACKLIST_DELETION); @@ -882,6 +890,7 @@ void TrackList::Permute(const std::vector &permutation) } auto n = begin(); RecalcPositions(n); + PermutationEvent(); } template @@ -1152,6 +1161,7 @@ void TrackList::SwapNodes(TrackNodePointer s1, TrackNodePointer s2) // Now correct the Index in the tracks, and other things RecalcPositions(s1); + PermutationEvent(); } bool TrackList::MoveUp(Track * t) diff --git a/src/Track.h b/src/Track.h index 1df407840..398a02587 100644 --- a/src/Track.h +++ b/src/Track.h @@ -483,6 +483,9 @@ class AUDACITY_DLL_API SyncLockedTracksIterator final : public TrackListIterator * Clear, and Contains, plus serialization of the list of tracks. */ +// Posted when tracks are reordered but otherwise unchanged. +DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_TRACKLIST_PERMUTED, -1); + // Posted when some track was added or changed its height. // The wxCommandEvent::GetClientData() method can be used to retrieve it. DECLARE_EXPORTED_EVENT_TYPE(AUDACITY_DLL_API, EVT_TRACKLIST_RESIZING, -1); @@ -607,6 +610,7 @@ private: void DoAssign(const TrackList &that); void RecalcPositions(TrackNodePointer node); + void PermutationEvent(); void DeletionEvent(); void ResizingEvent(TrackNodePointer node); diff --git a/src/TrackPanel.cpp b/src/TrackPanel.cpp index 76c059e49..fadbc2a74 100644 --- a/src/TrackPanel.cpp +++ b/src/TrackPanel.cpp @@ -1636,7 +1636,8 @@ void TrackPanel::DrawTracks(wxDC * dc) bool sliderFlag = bMultiToolDown; // The track artist actually draws the stuff inside each track - mTrackArtist->DrawTracks(GetTracks(), GetProject()->GetFirstVisible(), + auto first = GetProject()->GetFirstVisible(); + mTrackArtist->DrawTracks(GetTracks(), first.get(), *dc, region, tracksRect, clip, mViewInfo->selectedRegion, *mViewInfo, envelopeFlag, bigPointsFlag, sliderFlag); diff --git a/src/ViewInfo.cpp b/src/ViewInfo.cpp index f3ec6bd5f..b9802ba39 100644 --- a/src/ViewInfo.cpp +++ b/src/ViewInfo.cpp @@ -130,7 +130,6 @@ void ZoomInfo::FindIntervals ViewInfo::ViewInfo(double start, double screenDuration, double pixelsPerSecond) : ZoomInfo(start, pixelsPerSecond) , selectedRegion() - , track(NULL) , total(screenDuration) , sbarH(0) , sbarScreen(1) diff --git a/src/ViewInfo.h b/src/ViewInfo.h index e5dc80ce0..797bafd15 100644 --- a/src/ViewInfo.h +++ b/src/ViewInfo.h @@ -14,6 +14,7 @@ #include #include #include "SelectedRegion.h" +#include "MemoryX.h" class Track; @@ -157,7 +158,7 @@ public: // Scroll info - Track *track; // first visible track + std::weak_ptr track; // first visible track double total; // total width in secs // Current horizontal scroll bar positions, in pixels