diff --git a/src/export/Export.cpp b/src/export/Export.cpp index fd6bd6a48..b1fecec08 100644 --- a/src/export/Export.cpp +++ b/src/export/Export.cpp @@ -256,6 +256,18 @@ std::unique_ptr ExportPlugin::CreateMixer(const WaveTrackConstArray &inpu highQuality, mixerSpec); } +void ExportPlugin::InitProgress(std::unique_ptr &pDialog, + const wxString &title, const wxString &message) +{ + if (!pDialog) + pDialog = std::make_unique( title, message ); + else { + pDialog->SetTitle( title ); + pDialog->SetMessage( message ); + pDialog->Reinit(); + } +} + //---------------------------------------------------------------------------- // Export //---------------------------------------------------------------------------- @@ -849,7 +861,9 @@ bool Exporter::ExportTracks() } } ); + std::unique_ptr pDialog; auto result = mPlugins[mFormat]->Export(mProject, + pDialog, mChannels, mActualName.GetFullPath(), mSelectedOnly, diff --git a/src/export/Export.h b/src/export/Export.h index e35a6940c..653c6be33 100644 --- a/src/export/Export.h +++ b/src/export/Export.h @@ -30,6 +30,7 @@ class DirManager; class WaveTrack; class TrackList; class MixerSpec; +class ProgressDialog; class TimeTrack; class Mixer; using WaveTrackConstArray = std::vector < std::shared_ptr < const WaveTrack > >; @@ -97,6 +98,9 @@ public: /** \brief called to export audio into a file. * + * @param pDialog To be initialized with pointer to a NEW ProgressDialog if + * it was null, otherwise gives an existing dialog to be reused + * (working around a problem in wxWidgets for Mac; see bug 1600) * @param selectedOnly Set to true if all tracks should be mixed, to false * if only the selected tracks should be mixed and exported. * @param metadata A Tags object that will over-ride the one in *project and @@ -114,6 +118,7 @@ public: * ProgressResult::Stopped */ virtual ProgressResult Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, @@ -131,6 +136,10 @@ protected: double outRate, sampleFormat outFormat, bool highQuality = true, MixerSpec *mixerSpec = NULL); + // Create or recycle a dialog. + static void InitProgress(std::unique_ptr &pDialog, + const wxString &title, const wxString &message); + private: FormatInfoArray mFormatInfos; }; diff --git a/src/export/ExportCL.cpp b/src/export/ExportCL.cpp index c1405348f..7a331d7d5 100644 --- a/src/export/ExportCL.cpp +++ b/src/export/ExportCL.cpp @@ -287,6 +287,7 @@ public: wxWindow *OptionsCreate(wxWindow *parent, int format) override; ProgressResult Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, @@ -309,6 +310,7 @@ ExportCL::ExportCL() } ProgressResult ExportCL::Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectionOnly, @@ -448,10 +450,11 @@ ProgressResult ExportCL::Export(AudacityProject *project, } ); // Prepare the progress display - ProgressDialog progress(_("Export"), - selectionOnly ? - _("Exporting the selected audio using command-line encoder") : - _("Exporting the audio using command-line encoder")); + InitProgress( pDialog, _("Export"), + selectionOnly + ? _("Exporting the selected audio using command-line encoder") + : _("Exporting the audio using command-line encoder") ); + auto &progress = *pDialog; // Start piping the mixed data to the command while (updateResult == ProgressResult::Success && process.IsActive() && os->IsOk()) { diff --git a/src/export/ExportFFmpeg.cpp b/src/export/ExportFFmpeg.cpp index 7877e38c3..65a208da3 100644 --- a/src/export/ExportFFmpeg.cpp +++ b/src/export/ExportFFmpeg.cpp @@ -141,6 +141,7 @@ public: ///\param subformat index of export type ///\return true if export succeded ProgressResult Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, @@ -849,8 +850,10 @@ bool ExportFFmpeg::EncodeAudioFrame(int16_t *pFrame, size_t frameSize) ProgressResult ExportFFmpeg::Export(AudacityProject *project, - unsigned channels, const wxString &fName, - bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, const Tags *metadata, int subformat) + std::unique_ptr &pDialog, + unsigned channels, const wxString &fName, + bool selectionOnly, double t0, double t1, + MixerSpec *mixerSpec, const Tags *metadata, int subformat) { if (!CheckFFmpegPresence()) return ProgressResult::Cancelled; @@ -901,10 +904,13 @@ ProgressResult ExportFFmpeg::Export(AudacityProject *project, auto updateResult = ProgressResult::Success; { - ProgressDialog progress(wxFileName(fName).GetName(), - selectionOnly ? - wxString::Format(_("Exporting selected audio as %s"), ExportFFmpegOptions::fmts[mSubFormat].Description()) : - wxString::Format(_("Exporting the audio as %s"), ExportFFmpegOptions::fmts[mSubFormat].Description())); + InitProgress( pDialog, wxFileName(fName).GetName(), + selectionOnly + ? wxString::Format(_("Exporting selected audio as %s"), + ExportFFmpegOptions::fmts[mSubFormat].Description()) + : wxString::Format(_("Exporting the audio as %s"), + ExportFFmpegOptions::fmts[mSubFormat].Description()) ); + auto &progress = *pDialog; while (updateResult == ProgressResult::Success) { auto pcmNumSamples = mixer->Process(pcmBufferSize); diff --git a/src/export/ExportFLAC.cpp b/src/export/ExportFLAC.cpp index efc2d38dc..86cecab75 100644 --- a/src/export/ExportFLAC.cpp +++ b/src/export/ExportFLAC.cpp @@ -191,6 +191,7 @@ public: wxWindow *OptionsCreate(wxWindow *parent, int format) override; ProgressResult Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, @@ -222,6 +223,7 @@ ExportFLAC::ExportFLAC() } ProgressResult ExportFLAC::Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned numChannels, const wxString &fName, bool selectionOnly, @@ -354,10 +356,11 @@ ProgressResult ExportFLAC::Export(AudacityProject *project, ArraysOf tmpsmplbuf{ numChannels, SAMPLES_PER_RUN, true }; - ProgressDialog progress(wxFileName(fName).GetName(), - selectionOnly ? - _("Exporting the selected audio as FLAC") : - _("Exporting the audio as FLAC")); + InitProgress( pDialog, wxFileName(fName).GetName(), + selectionOnly + ? _("Exporting the selected audio as FLAC") + : _("Exporting the audio as FLAC") ); + auto &progress = *pDialog; while (updateResult == ProgressResult::Success) { auto samplesThisRun = mixer->Process(SAMPLES_PER_RUN); diff --git a/src/export/ExportMP2.cpp b/src/export/ExportMP2.cpp index 0b790962b..5beafd680 100644 --- a/src/export/ExportMP2.cpp +++ b/src/export/ExportMP2.cpp @@ -174,6 +174,7 @@ public: wxWindow *OptionsCreate(wxWindow *parent, int format) override; ProgressResult Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, @@ -204,6 +205,7 @@ ExportMP2::ExportMP2() } ProgressResult ExportMP2::Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectionOnly, double t0, double t1, MixerSpec *mixerSpec, const Tags *metadata, int WXUNUSED(subformat)) @@ -272,10 +274,13 @@ ProgressResult ExportMP2::Export(AudacityProject *project, stereo ? 2 : 1, pcmBufferSize, true, rate, int16Sample, true, mixerSpec); - ProgressDialog progress(wxFileName(fName).GetName(), - selectionOnly ? - wxString::Format(_("Exporting selected audio at %ld kbps"), bitrate) : - wxString::Format(_("Exporting the audio at %ld kbps"), bitrate)); + InitProgress( pDialog, wxFileName(fName).GetName(), + selectionOnly + ? wxString::Format(_("Exporting selected audio at %ld kbps"), + bitrate) + : wxString::Format(_("Exporting the audio at %ld kbps"), + bitrate) ); + auto &progress = *pDialog; while (updateResult == ProgressResult::Success) { auto pcmNumSamples = mixer->Process(pcmBufferSize); diff --git a/src/export/ExportMP3.cpp b/src/export/ExportMP3.cpp index 475a25f00..6a7c8f231 100644 --- a/src/export/ExportMP3.cpp +++ b/src/export/ExportMP3.cpp @@ -1610,6 +1610,7 @@ public: wxWindow *OptionsCreate(wxWindow *parent, int format) override; ProgressResult Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, @@ -1670,6 +1671,7 @@ int ExportMP3::SetNumExportChannels() ProgressResult ExportMP3::Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectionOnly, @@ -1858,7 +1860,8 @@ ProgressResult ExportMP3::Export(AudacityProject *project, brate); } - ProgressDialog progress(wxFileName(fName).GetName(), title); + InitProgress( pDialog, wxFileName(fName).GetName(), title ); + auto &progress = *pDialog; while (updateResult == ProgressResult::Success) { auto blockLen = mixer->Process(inSamples); diff --git a/src/export/ExportMultiple.cpp b/src/export/ExportMultiple.cpp index ecc25af52..549a29d29 100644 --- a/src/export/ExportMultiple.cpp +++ b/src/export/ExportMultiple.cpp @@ -749,6 +749,7 @@ ProgressResult ExportMultiple::ExportMultipleByLabel(bool byName, ExportKit activeSetting; // pointer to the settings in use for this export /* Go round again and do the exporting (so this run is slow but * non-interactive) */ + std::unique_ptr pDialog; for (count = 0; count < numFiles; count++) { /* get the settings to use for the export from the array */ activeSetting = exportSettings[count]; @@ -757,7 +758,8 @@ ProgressResult ExportMultiple::ExportMultipleByLabel(bool byName, continue; // Export it - ok = DoExport(channels, activeSetting.destfile, false, activeSetting.t0, activeSetting.t1, activeSetting.filetags); + ok = DoExport(pDialog, channels, activeSetting.destfile, false, + activeSetting.t0, activeSetting.t1, activeSetting.filetags); if (ok != ProgressResult::Success && ok != ProgressResult::Stopped) { break; } @@ -887,6 +889,7 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName, // loop int count = 0; // count the number of sucessful runs ExportKit activeSetting; // pointer to the settings in use for this export + std::unique_ptr pDialog; for (tr = iter.First(mTracks); tr != NULL; tr = iter.Next()) { // Want only non-muted wave tracks. @@ -918,7 +921,9 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName, tr2->SetSelected(true); // Export the data. "channels" are per track. - ok = DoExport(activeSetting.channels, activeSetting.destfile, true, activeSetting.t0, activeSetting.t1, activeSetting.filetags); + ok = DoExport(pDialog, + activeSetting.channels, activeSetting.destfile, true, + activeSetting.t0, activeSetting.t1, activeSetting.filetags); // Stop if an error occurred if (ok != ProgressResult::Success && ok != ProgressResult::Stopped) { @@ -932,7 +937,8 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName, return ok ; } -ProgressResult ExportMultiple::DoExport(unsigned channels, +ProgressResult ExportMultiple::DoExport(std::unique_ptr &pDialog, + unsigned channels, const wxFileName &inName, bool selectedOnly, double t0, @@ -1001,6 +1007,7 @@ ProgressResult ExportMultiple::DoExport(unsigned channels, // Call the format export routine success = mPlugins[mPluginIndex]->Export(mProject, + pDialog, channels, fullPath, selectedOnly, diff --git a/src/export/ExportMultiple.h b/src/export/ExportMultiple.h index d2fbbf262..6d617c030 100644 --- a/src/export/ExportMultiple.h +++ b/src/export/ExportMultiple.h @@ -75,7 +75,8 @@ private: * @param t1 End time for export * @param tags Metadata to include in the file (if possible). */ - ProgressResult DoExport(unsigned channels, + ProgressResult DoExport(std::unique_ptr &pDialog, + unsigned channels, const wxFileName &name, bool selectedOnly, double t0, diff --git a/src/export/ExportOGG.cpp b/src/export/ExportOGG.cpp index 51b420cb7..3ab2ab3d2 100644 --- a/src/export/ExportOGG.cpp +++ b/src/export/ExportOGG.cpp @@ -133,6 +133,7 @@ public: wxWindow *OptionsCreate(wxWindow *parent, int format) override; ProgressResult Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, @@ -159,6 +160,7 @@ ExportOGG::ExportOGG() } ProgressResult ExportOGG::Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned numChannels, const wxString &fName, bool selectionOnly, @@ -281,10 +283,11 @@ ProgressResult ExportOGG::Export(AudacityProject *project, numChannels, SAMPLES_PER_RUN, false, rate, floatSample, true, mixerSpec); - ProgressDialog progress(wxFileName(fName).GetName(), - selectionOnly ? - _("Exporting the selected audio as Ogg Vorbis") : - _("Exporting the audio as Ogg Vorbis")); + InitProgress( pDialog, wxFileName(fName).GetName(), + selectionOnly + ? _("Exporting the selected audio as Ogg Vorbis") + : _("Exporting the audio as Ogg Vorbis") ); + auto &progress = *pDialog; while (updateResult == ProgressResult::Success && !eos) { float **vorbis_buffer = vorbis_analysis_buffer(&dsp, SAMPLES_PER_RUN); diff --git a/src/export/ExportPCM.cpp b/src/export/ExportPCM.cpp index 44c819181..af14e678f 100644 --- a/src/export/ExportPCM.cpp +++ b/src/export/ExportPCM.cpp @@ -319,6 +319,7 @@ public: wxWindow *OptionsCreate(wxWindow *parent, int format) override; ProgressResult Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned channels, const wxString &fName, bool selectedOnly, @@ -390,6 +391,7 @@ ExportPCM::ExportPCM() * file type, or giving the user full control over libsndfile. */ ProgressResult ExportPCM::Export(AudacityProject *project, + std::unique_ptr &pDialog, unsigned numChannels, const wxString &fName, bool selectionOnly, @@ -489,12 +491,13 @@ ProgressResult ExportPCM::Export(AudacityProject *project, info.channels, maxBlockLen, true, rate, format, true, mixerSpec); - ProgressDialog progress(wxFileName(fName).GetName(), - selectionOnly ? - wxString::Format(_("Exporting the selected audio as %s"), - formatStr) : - wxString::Format(_("Exporting the audio as %s"), - formatStr)); + InitProgress( pDialog, wxFileName(fName).GetName(), + selectionOnly + ? wxString::Format(_("Exporting the selected audio as %s"), + formatStr) + : wxString::Format(_("Exporting the audio as %s"), + formatStr) ); + auto &progress = *pDialog; while (updateResult == ProgressResult::Success) { sf_count_t samplesWritten; diff --git a/src/widgets/ProgressDialog.cpp b/src/widgets/ProgressDialog.cpp index 4fafd222d..a33bbe53b 100644 --- a/src/widgets/ProgressDialog.cpp +++ b/src/widgets/ProgressDialog.cpp @@ -997,7 +997,6 @@ END_EVENT_TABLE() ProgressDialog::ProgressDialog() : wxDialogWrapper() { - Init(); } ProgressDialog::ProgressDialog(const wxString & title, @@ -1006,8 +1005,6 @@ ProgressDialog::ProgressDialog(const wxString & title, const wxString & sRemainingLabelText /* = wxEmptyString */) : wxDialogWrapper() { - Init(); - Create(title, message, flags, sRemainingLabelText); } @@ -1017,8 +1014,6 @@ ProgressDialog::ProgressDialog(const wxString & title, const wxString & sRemainingLabelText /* = wxEmptyString */) : wxDialogWrapper() { - Init(); - Create(title, columns, flags, sRemainingLabelText); } @@ -1059,10 +1054,6 @@ ProgressDialog::~ProgressDialog() void ProgressDialog::Init() { - mLastValue = 0; - mDisable = NULL; - mIsTransparent = true; - // There's a problem where the focus is not returned to the window that had // it before creating this object. The reason is because the focus events // that are sent to the parent window after the wxWindowDisabler are created @@ -1082,6 +1073,34 @@ void ProgressDialog::Init() #endif } +void ProgressDialog::Reinit() +{ + mLastValue = 0; + + mStartTime = wxGetLocalTimeMillis().GetValue(); + mLastUpdate = mStartTime; + mYieldTimer = mStartTime; + mCancel = false; + mStop = false; + + // Because wxGTK is very sensitive about maintaining focus when + // this window is not shown, we always show it. But, since we + // want a 500ms delay before it's actually visible for those + // quick tasks, we show it as transparent. If the initial + // delay is exceeded, then we reset the dialog to full opacity. + SetTransparent(0); + mIsTransparent = true; + + auto button = FindWindowById(wxID_CANCEL, this); + if (button) + button->Enable(); + button = FindWindowById(wxID_OK, this); + if (button) + button->Enable(); + + wxDialogWrapper::Show(true); +} + // Add a NEW text column each time this is called. void ProgressDialog::AddMessageAsColumn(wxBoxSizer * pSizer, const MessageColumn & column, @@ -1138,6 +1157,8 @@ bool ProgressDialog::Create(const wxString & title, int flags /* = pdlgDefaultFlags */, const wxString & sRemainingLabelText /* = wxEmptyString */) { + Init(); + wxWindow *parent = GetParentForModalDialog(NULL, 0); // Set this boolean to indicate if we are using the "Elapsed" labels @@ -1267,21 +1288,7 @@ bool ProgressDialog::Create(const wxString & title, Centre(wxCENTER_FRAME | wxBOTH); - mStartTime = wxGetLocalTimeMillis().GetValue(); - mLastUpdate = mStartTime; - mYieldTimer = mStartTime; - mCancel = false; - mStop = false; - - // Because wxGTK is very sensitive about maintaining focus when - // this window is not shown, we always show it. But, since we - // want a 500ms delay before it's actually visible for those - // quick tasks, we show it as transparent. If the initial - // delay is exceeded, then we reset the dialog to full opacity. - SetTransparent(0); - mIsTransparent = true; - - wxDialogWrapper::Show(true); + Reinit(); // Even though we won't necessarily show the dialog due to the 500ms // delay, we MUST disable other windows/menus anyway since we run the risk diff --git a/src/widgets/ProgressDialog.h b/src/widgets/ProgressDialog.h index 990c79a16..868ece199 100644 --- a/src/widgets/ProgressDialog.h +++ b/src/widgets/ProgressDialog.h @@ -86,6 +86,8 @@ public: int flags = pdlgDefaultFlags, const wxString & sRemainingLabelText = wxEmptyString); + void Reinit(); + protected: bool Create(const wxString & title, const MessageTable & columns, @@ -103,7 +105,7 @@ public: void SetMessage(const wxString & message); protected: - wxWindow *mHadFocus; + wxWeakRef mHadFocus; wxStaticText *mElapsed; wxStaticText *mRemaining;