diff --git a/src/AudacityApp.cpp b/src/AudacityApp.cpp index 9d9b9ffae..3ba24552f 100644 --- a/src/AudacityApp.cpp +++ b/src/AudacityApp.cpp @@ -275,7 +275,7 @@ void QuitAudacity(bool bForce) // BG: Are there any projects open? //- if (!gAudacityProjects.IsEmpty()) /*start+*/ - if (gAudacityProjects.IsEmpty()) + if (gAudacityProjects.empty()) { #ifdef __WXMAC__ AudacityProject::DeleteClipboard(); @@ -285,8 +285,10 @@ void QuitAudacity(bool bForce) /*end+*/ { SaveWindowSize(); - while (gAudacityProjects.Count()) + while (gAudacityProjects.size()) { + // Closing the project has global side-effect + // of deletion from gAudacityProjects if (bForce) { gAudacityProjects[0]->Close(true); @@ -339,12 +341,12 @@ void SaveWindowSize() bool validWindowForSaveWindowSize = FALSE; AudacityProject * validProject = NULL; bool foundIconizedProject = FALSE; - size_t numProjects = gAudacityProjects.Count(); + size_t numProjects = gAudacityProjects.size(); for (size_t i = 0; i < numProjects; i++) { if (!gAudacityProjects[i]->IsIconized()) { validWindowForSaveWindowSize = TRUE; - validProject = gAudacityProjects[i]; + validProject = gAudacityProjects[i].get(); i = numProjects; } else @@ -370,7 +372,7 @@ void SaveWindowSize() else { if (foundIconizedProject) { - validProject = gAudacityProjects[0]; + validProject = gAudacityProjects[0].get(); bool wndMaximized = validProject->IsMaximized(); wxRect normalRect = validProject->GetNormalizedWindowState(); // store only the normal rectangle because the itemized rectangle @@ -502,7 +504,7 @@ static gboolean save_yourself_cb(GnomeClient *client, return TRUE; } - if (gAudacityProjects.IsEmpty()) { + if (gAudacityProjects.empty()) { return TRUE; } @@ -723,7 +725,7 @@ void AudacityApp::MacNewFile() // This method should only be used on the Mac platform // when no project windows are open. - if (gAudacityProjects.GetCount() == 0) { + if (gAudacityProjects.size() == 0) { CreateNewAudacityProject(); } } @@ -886,19 +888,19 @@ void AudacityApp::OnTimer(wxTimerEvent& WXUNUSED(event)) if (ShouldShowMissingAliasedFileWarning()) { // find which project owns the blockfile // note: there may be more than 1, but just go with the first one. - size_t numProjects = gAudacityProjects.Count(); + size_t numProjects = gAudacityProjects.size(); wxString missingFileName; AudacityProject *offendingProject = NULL; m_LastMissingBlockFileLock.Lock(); if (numProjects == 1) { // if there is only one project open, no need to search - offendingProject = gAudacityProjects[0]; + offendingProject = gAudacityProjects[0].get(); } else if (numProjects > 1) { for (size_t i = 0; i < numProjects; i++) { // search each project for the blockfile if (gAudacityProjects[i]->GetDirManager()->ContainsBlockFile(m_LastMissingBlockFile)) { - offendingProject = gAudacityProjects[i]; + offendingProject = gAudacityProjects[i].get(); break; } } @@ -1973,8 +1975,10 @@ void AudacityApp::OnEndSession(wxCloseEvent & event) // Try to close each open window. If the user hits Cancel // in a Save Changes dialog, don't continue. - if (!gAudacityProjects.IsEmpty()) { - while (gAudacityProjects.Count()) { + if (!gAudacityProjects.empty()) { + while (gAudacityProjects.size()) { + // Closing the project has side-effect of + // deletion from gAudacityProjects if (force) { gAudacityProjects[0]->Close(true); } @@ -2077,7 +2081,7 @@ void AudacityApp::OnMenuNew(wxCommandEvent & event) // this happens, and enable the same code to be present on // all platforms. - if(gAudacityProjects.GetCount() == 0) + if(gAudacityProjects.size() == 0) CreateNewAudacityProject(); else event.Skip(); @@ -2093,7 +2097,7 @@ void AudacityApp::OnMenuOpen(wxCommandEvent & event) // all platforms. - if(gAudacityProjects.GetCount() == 0) + if(gAudacityProjects.size() == 0) AudacityProject::OpenFiles(NULL); else event.Skip(); @@ -2109,7 +2113,7 @@ void AudacityApp::OnMenuPreferences(wxCommandEvent & event) // this happens, and enable the same code to be present on // all platforms. - if(gAudacityProjects.GetCount() == 0) { + if(gAudacityProjects.size() == 0) { GlobalPrefsDialog dialog(NULL /* parent */ ); dialog.ShowModal(); } @@ -2127,12 +2131,12 @@ void AudacityApp::OnMenuExit(wxCommandEvent & event) // all platforms. // LL: Removed "if" to allow closing based on final project count. - // if(gAudacityProjects.GetCount() == 0) + // if(gAudacityProjects.size() == 0) QuitAudacity(); // LL: Veto quit if projects are still open. This can happen // if the user selected Cancel in a Save dialog. - event.Skip(gAudacityProjects.GetCount() == 0); + event.Skip(gAudacityProjects.size() == 0); } diff --git a/src/DeviceManager.cpp b/src/DeviceManager.cpp index fb61089dc..145a60624 100644 --- a/src/DeviceManager.cpp +++ b/src/DeviceManager.cpp @@ -300,7 +300,7 @@ void DeviceManager::Rescan() // Hosts may have disappeared or appeared so a complete repopulate is needed. if (m_inited) { DeviceToolBar *dt; - for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { + for (size_t i = 0; i < gAudacityProjects.size(); i++) { dt = gAudacityProjects[i]->GetDeviceToolBar(); dt->RefillCombos(); } diff --git a/src/MemoryX.h b/src/MemoryX.h index 43b23854e..5058a6e6c 100644 --- a/src/MemoryX.h +++ b/src/MemoryX.h @@ -670,15 +670,42 @@ public: movable_ptr_with_deleter() {}; movable_ptr_with_deleter(T* p, const Deleter &d) : movable_ptr_with_deleter_base( p, d ) {} - movable_ptr_with_deleter(const movable_ptr_with_deleter &that) = default; + +#ifdef __AUDACITY_OLD_STD__ + + // copy + movable_ptr_with_deleter(const movable_ptr_with_deleter &that) + : movable_ptr_with_deleter_base < T, Deleter > ( that ) + { + } + + movable_ptr_with_deleter &operator= (const movable_ptr_with_deleter& that) + { + if (this != &that) { + ((movable_ptr_with_deleter_base&)(*this)) = + that; + } + return *this; + } + +#else + + // move + movable_ptr_with_deleter(movable_ptr_with_deleter &&that) + : movable_ptr_with_deleter_base < T, Deleter > ( std::move(that) ) + { + } + movable_ptr_with_deleter &operator= (movable_ptr_with_deleter&& that) { if (this != &that) { ((movable_ptr_with_deleter_base&)(*this)) = - std::move(that); + std::move(that); } return *this; } + +#endif }; template diff --git a/src/Menus.cpp b/src/Menus.cpp index 08a772991..a03dfd238 100644 --- a/src/Menus.cpp +++ b/src/Menus.cpp @@ -1828,7 +1828,7 @@ void AudacityProject::ModifyAllProjectToolbarMenus() { AProjectArray::iterator i; for (i = gAudacityProjects.begin(); i != gAudacityProjects.end(); ++i) { - ((AudacityProject *)*i)->ModifyToolbarMenus(); + (*i)->ModifyToolbarMenus(); } } @@ -2260,9 +2260,9 @@ void AudacityProject::OnPlayStop() //find out which project we need; AudacityProject* otherProject = NULL; - for(unsigned i=0; iIsStreamActive(gAudacityProjects[i]->GetAudioIOToken())) { - otherProject=gAudacityProjects[i]; + otherProject=gAudacityProjects[i].get(); break; } } @@ -3554,8 +3554,8 @@ void AudacityProject::OnManagePluginsMenu(EffectType type) { if (PluginManager::Get().ShowManager(this, type)) { - for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { - AudacityProject *p = gAudacityProjects[i]; + for (size_t i = 0; i < gAudacityProjects.size(); i++) { + AudacityProject *p = gAudacityProjects[i].get(); p->RebuildMenuBar(); #if defined(__WXGTK__) @@ -3835,8 +3835,8 @@ void AudacityProject::OnPreferences() // LL: Moved from PrefsDialog since wxWidgets on OSX can't deal with // rebuilding the menus while the PrefsDialog is still in the modal // state. - for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { - AudacityProject *p = gAudacityProjects[i]; + for (size_t i = 0; i < gAudacityProjects.size(); i++) { + AudacityProject *p = gAudacityProjects[i].get(); p->RebuildMenuBar(); p->RebuildOtherMenus(); diff --git a/src/MenusMac.cpp b/src/MenusMac.cpp index 23e24da19..33b717490 100644 --- a/src/MenusMac.cpp +++ b/src/MenusMac.cpp @@ -46,7 +46,7 @@ void AudacityProject::OnMacMinimize() void AudacityProject::OnMacMinimizeAll() { for (const auto project : gAudacityProjects) { - DoMacMinimize(project); + DoMacMinimize(project.get()); } } diff --git a/src/Project.cpp b/src/Project.cpp index 208d9862f..a2f125f2b 100644 --- a/src/Project.cpp +++ b/src/Project.cpp @@ -527,10 +527,14 @@ AudacityProject *CreateNewAudacityProject() GetNextWindowPlacement(&wndRect, &bMaximized, &bIconized); //Create and show a NEW project - AudacityProject *p = new AudacityProject(NULL, -1, - wxDefaultPosition, - wxSize(wndRect.width, wndRect.height)); - gAudacityProjects.Add(p); + gAudacityProjects.push_back( + make_movable_with_deleter > + ({}, + nullptr, -1, + wxDefaultPosition, + wxSize(wndRect.width, wndRect.height)) + ); + const auto p = gAudacityProjects.back().get(); // wxGTK3 seems to need to require creating the window using default position // and then manually positioning it. @@ -563,21 +567,21 @@ AudacityProject *CreateNewAudacityProject() void RedrawAllProjects() { - size_t len = gAudacityProjects.GetCount(); + size_t len = gAudacityProjects.size(); for (size_t i = 0; i < len; i++) gAudacityProjects[i]->RedrawProject(); } void RefreshCursorForAllProjects() { - size_t len = gAudacityProjects.GetCount(); + size_t len = gAudacityProjects.size(); for (size_t i = 0; i < len; i++) gAudacityProjects[i]->RefreshCursor(); } AUDACITY_DLL_API void CloseAllProjects() { - size_t len = gAudacityProjects.GetCount(); + size_t len = gAudacityProjects.size(); for (size_t i = 0; i < len; i++) gAudacityProjects[i]->Close(); @@ -712,7 +716,7 @@ void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized) windowRect = defaultRect; } - if (gAudacityProjects.IsEmpty()) { + if (gAudacityProjects.empty()) { if (*pMaximized || *pIconized) { *nextRect = normalRect; } @@ -726,11 +730,11 @@ void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized) else { bool validWindowSize = false; AudacityProject * validProject = NULL; - size_t numProjects = gAudacityProjects.Count(); + size_t numProjects = gAudacityProjects.size(); for (int i = numProjects; i > 0 ; i--) { if (!gAudacityProjects[i-1]->IsIconized()) { validWindowSize = true; - validProject = gAudacityProjects[i-1]; + validProject = gAudacityProjects[i-1].get(); break; } } @@ -1967,7 +1971,7 @@ void AudacityProject::OnIconize(wxIconizeEvent &event) unsigned int i; - for(i=0;imIconized ) VisibleProjectCount++; @@ -2365,7 +2369,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) // DanH: If we're definitely about to quit, DELETE the clipboard. // Doing this after Deref'ing the DirManager causes problems. - if ((gAudacityProjects.GetCount() == 1) && (quitOnClose || gIsQuitting)) + if ((gAudacityProjects.size() == 1) && (quitOnClose || gIsQuitting)) DeleteClipboard(); // JKC: For Win98 and Linux do not detach the menu bar. @@ -2445,15 +2449,21 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) // have been deleted before this. mDirManager.reset(); + AProjectHolder pSelf; { ODLocker locker{ &AudacityProject::AllProjectDeleteMutex() }; - gAudacityProjects.Remove(this); + auto end = gAudacityProjects.end(); + auto it = std::find_if(gAudacityProjects.begin(), end, + [this] (const AProjectHolder &p) { return p.get() == this; }); + wxASSERT( it != end ); + pSelf = std::move( *it ); + gAudacityProjects.erase(it); } if (gActiveProject == this) { // Find a NEW active project - if (gAudacityProjects.Count() > 0) { - SetActiveProject(gAudacityProjects[0]); + if (gAudacityProjects.size() > 0) { + SetActiveProject(gAudacityProjects[0].get()); } else { SetActiveProject(NULL); @@ -2466,7 +2476,7 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) gAudioIO->SetListener(gActiveProject); } - if (gAudacityProjects.IsEmpty() && !gIsQuitting) { + if (gAudacityProjects.empty() && !gIsQuitting) { #if !defined(__WXMAC__) if (quitOnClose) { @@ -2484,7 +2494,8 @@ void AudacityProject::OnCloseWindow(wxCloseEvent & event) NULL, &mViewInfo); - Destroy(); + // Destroys this + pSelf.reset(); mRuler = nullptr; mIsBeingDeleted = true; @@ -2611,7 +2622,7 @@ wxArrayString AudacityProject::ShowOpenDialog(const wxString &extraformat, const bool AudacityProject::IsAlreadyOpen(const wxString & projPathName) { const wxFileName newProjPathName(projPathName); - size_t numProjects = gAudacityProjects.Count(); + size_t numProjects = gAudacityProjects.size(); for (size_t i = 0; i < numProjects; i++) { if (newProjPathName.SameAs(gAudacityProjects[i]->mFileName)) @@ -5332,7 +5343,7 @@ bool AudacityProject::ExportFromTimerRecording(wxFileName fnFile, int iFormat, i } int AudacityProject::GetOpenProjectCount() { - return gAudacityProjects.Count(); + return gAudacityProjects.size(); } bool AudacityProject::IsProjectSaved() { diff --git a/src/Project.h b/src/Project.h index d464b8cfd..ede23514c 100644 --- a/src/Project.h +++ b/src/Project.h @@ -110,7 +110,9 @@ void GetDefaultWindowRect(wxRect *defRect); void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized); bool IsWindowAccessible(wxRect *requestedRect); -WX_DEFINE_ARRAY(AudacityProject *, AProjectArray); +using AProjectHolder = + movable_ptr_with_deleter< AudacityProject, Destroyer< AudacityProject > >; +using AProjectArray = std::vector< AProjectHolder >; extern AProjectArray gAudacityProjects; diff --git a/src/export/Export.cpp b/src/export/Export.cpp index de96a60b1..c5b0748a5 100644 --- a/src/export/Export.cpp +++ b/src/export/Export.cpp @@ -622,9 +622,9 @@ bool Exporter::GetFilename() // Also, this can only happen for uncompressed audio. bool overwritingMissingAlias; overwritingMissingAlias = false; - for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { + for (size_t i = 0; i < gAudacityProjects.size(); i++) { AliasedFileArray aliasedFiles; - FindDependencies(gAudacityProjects[i], aliasedFiles); + FindDependencies(gAudacityProjects[i].get(), aliasedFiles); for (const auto &aliasedFile : aliasedFiles) { if (mFilename.GetFullPath() == aliasedFile.mFileName.GetFullPath() && !mFilename.FileExists()) { diff --git a/src/ondemand/ODTask.cpp b/src/ondemand/ODTask.cpp index 93b5e5f84..57d248313 100644 --- a/src/ondemand/ODTask.cpp +++ b/src/ondemand/ODTask.cpp @@ -129,9 +129,9 @@ void ODTask::DoSome(float amountWork) //we did a bit of progress - we should allow a resave. ODLocker locker{ &AudacityProject::AllProjectDeleteMutex() }; - for(unsigned i=0; iGetUndoManager()->SetODChangesFlag(); @@ -153,9 +153,9 @@ void ODTask::DoSome(float amountWork) wxCommandEvent event( EVT_ODTASK_COMPLETE ); ODLocker locker{ &AudacityProject::AllProjectDeleteMutex() }; - for(unsigned i=0; iGetEventHandler()->AddPendingEvent(event); diff --git a/src/prefs/PrefsDialog.cpp b/src/prefs/PrefsDialog.cpp index 4d14e880f..ba61fde45 100644 --- a/src/prefs/PrefsDialog.cpp +++ b/src/prefs/PrefsDialog.cpp @@ -437,7 +437,7 @@ void PrefsDialog::OnOK(wxCommandEvent & WXUNUSED(event)) // LL: wxMac can't handle recreating the menus when this dialog is still active, // so AudacityProject::UpdatePrefs() or any of the routines it calls must // not cause AudacityProject::RebuildMenuBar() to be executed. - for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { + for (size_t i = 0; i < gAudacityProjects.size(); i++) { gAudacityProjects[i]->UpdatePrefs(); } diff --git a/src/toolbars/DeviceToolBar.cpp b/src/toolbars/DeviceToolBar.cpp index 8ec7abe64..21b8268fc 100644 --- a/src/toolbars/DeviceToolBar.cpp +++ b/src/toolbars/DeviceToolBar.cpp @@ -762,7 +762,7 @@ void DeviceToolBar::OnChoice(wxCommandEvent &event) } // Update all projects' DeviceToolBar. - for (size_t i = 0; i < gAudacityProjects.GetCount(); i++) { + for (size_t i = 0; i < gAudacityProjects.size(); i++) { gAudacityProjects[i]->GetDeviceToolBar()->UpdatePrefs(); } }