1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-07-14 07:37:43 +02:00

Merge release-3.0.3 into master

Conflicts:
	src/AboutDialog.cpp
	src/prefs/ApplicationPrefs.cpp
This commit is contained in:
Paul Licameli 2021-07-12 14:41:27 -04:00
commit d0d64bf025
32 changed files with 464 additions and 192 deletions

View File

@ -74,9 +74,9 @@ jobs:
cache-name: cache-conan-modules cache-name: cache-conan-modules
with: with:
path: ${{ env.CONAN_USER_HOME }} path: ${{ env.CONAN_USER_HOME }}
key: host-${{ matrix.config.name }}-${{ hashFiles('cmake-proxies/CMakeLists.txt') }} key: host-3-${{ matrix.config.name }}-${{ hashFiles('cmake-proxies/CMakeLists.txt') }}
restore-keys: | restore-keys: |
host-${{ matrix.config.name }}- host-3-${{ matrix.config.name }}-
- name: Configure - name: Configure
env: env:

View File

@ -19,7 +19,7 @@ endif ()
# still link to the alpha manual online. # still link to the alpha manual online.
# Set this value to 0 for alpha, 1 for beta, 2 for release builds # Set this value to 0 for alpha, 1 for beta, 2 for release builds
set( AUDACITY_BUILD_LEVEL 0 ) set( AUDACITY_BUILD_LEVEL 0 CACHE STRING "0 for alpha, 1 for beta, 2 for release builds" )
# The Audacity version # The Audacity version
# Increment as appropriate after release of a new version, and set back # Increment as appropriate after release of a new version, and set back

View File

@ -246,7 +246,7 @@ namespace
{ {
static constexpr int MaxUserCommentLength = 2000; static constexpr int MaxUserCommentLength = 2000;
auto frame = new wxFrame( auto dialog = new wxDialog(
nullptr, nullptr,
wxID_ANY, wxID_ANY,
_("Problem Report for Audacity"), _("Problem Report for Audacity"),
@ -254,83 +254,89 @@ namespace
wxDefaultSize, wxDefaultSize,
wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)//disable frame resize wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)//disable frame resize
); );
frame->SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
//fixes focus issue with Windows build-in screen reader, but breaks VoiceOver
#if defined(__WXMSW__)
dialog->SetFocus();
#endif
auto mainLayout = new wxBoxSizer(wxVERTICAL); auto mainLayout = new wxBoxSizer(wxVERTICAL);
auto headerText = new wxStaticText(frame, wxID_ANY, header);
headerText->SetFont(wxFont(wxFontInfo().Bold()));
auto headerLayout = new wxBoxSizer(wxHORIZONTAL); auto headerLayout = new wxBoxSizer(wxHORIZONTAL);
headerLayout->Add(new wxStaticBitmap(frame, wxID_ANY, wxIcon(warning))); headerLayout->Add(new wxStaticBitmap(dialog, wxID_ANY, wxIcon(warning)));
headerLayout->AddSpacer(5); headerLayout->AddSpacer(5);
auto headerText = new wxStaticText(dialog, wxID_ANY, header);
headerText->SetFont(wxFont(wxFontInfo().Bold()));
headerLayout->Add(headerText, wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL)); headerLayout->Add(headerText, wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
mainLayout->Add(headerLayout, wxSizerFlags().Border(wxALL));
if (onSend != nullptr)
{
mainLayout->AddSpacer(5);
mainLayout->Add(new wxStaticText(dialog, wxID_ANY, _("Click \"Send\" to submit the report to Audacity. This information is collected anonymously.")), wxSizerFlags().Border(wxALL));
}
mainLayout->AddSpacer(10);
mainLayout->Add(new wxStaticText(dialog, wxID_ANY, _("Problem details")), wxSizerFlags().Border(wxALL));
auto dumpTextCtrl = new wxTextCtrl(dialog, wxID_ANY, dump, wxDefaultPosition, wxSize(500, 300), wxTE_RICH | wxTE_READONLY | wxTE_MULTILINE | wxTE_DONTWRAP);
dumpTextCtrl->SetFont(wxFont(wxFontInfo().Family(wxFONTFAMILY_TELETYPE)));
dumpTextCtrl->ShowPosition(0);//scroll to top
mainLayout->Add(dumpTextCtrl, wxSizerFlags().Border(wxALL).Expand());
auto buttonsLayout = new wxBoxSizer(wxHORIZONTAL); auto buttonsLayout = new wxBoxSizer(wxHORIZONTAL);
wxTextCtrl* commentCtrl = nullptr; wxTextCtrl* commentCtrl = nullptr;
if (onSend != nullptr) if (onSend != nullptr)
{ {
commentCtrl = new wxTextCtrl(frame, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(500, 100), wxTE_MULTILINE); mainLayout->AddSpacer(10);
mainLayout->Add(new wxStaticText(dialog, wxID_ANY, _("Comments")), wxSizerFlags().Border(wxALL));
commentCtrl = new wxTextCtrl(dialog, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(500, 100), wxTE_MULTILINE);
commentCtrl->SetMaxLength(MaxUserCommentLength); commentCtrl->SetMaxLength(MaxUserCommentLength);
mainLayout->Add(commentCtrl, wxSizerFlags().Border(wxALL).Expand());
} }
if (onSend != nullptr) if (onSend != nullptr && commentCtrl != nullptr)
{ {
auto okButton = new wxButton(frame, wxID_ANY, XC("&Don't send", "crash reporter button")); auto dontSendButton = new wxButton(dialog, wxID_ANY, XC("&Don't send", "crash reporter button"));
auto sendButton = new wxButton(frame, wxID_ANY, XC("&Send", "crash reporter button")); auto sendButton = new wxButton(dialog, wxID_ANY, XC("&Send", "crash reporter button"));
okButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) dontSendButton->Bind(wxEVT_BUTTON, [dialog](wxCommandEvent&)
{ {
frame->Close(true); dialog->Close(true);
}); });
sendButton->Bind(wxEVT_BUTTON, [frame, commentCtrl, onSend](wxCommandEvent&) sendButton->Bind(wxEVT_BUTTON, [dialog, commentCtrl, onSend](wxCommandEvent&)
{ {
if (onSend(commentCtrl->GetValue())) if (onSend(commentCtrl->GetValue()))
{ {
frame->Close(true); dialog->Close(true);
} }
}); });
buttonsLayout->Add(okButton); buttonsLayout->Add(dontSendButton);
buttonsLayout->AddSpacer(5); buttonsLayout->AddSpacer(5);
buttonsLayout->Add(sendButton); buttonsLayout->Add(sendButton);
} }
else else
{ {
auto okButton = new wxButton(frame, wxID_OK, wxT("OK")); auto okButton = new wxButton(dialog, wxID_OK, wxT("OK"));
okButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&) okButton->Bind(wxEVT_BUTTON, [dialog](wxCommandEvent&)
{ {
frame->Close(true); dialog->Close(true);
}); });
buttonsLayout->Add(okButton); buttonsLayout->Add(okButton);
} }
mainLayout->Add(headerLayout, wxSizerFlags().Border(wxALL));
if (onSend != nullptr)
{
mainLayout->AddSpacer(5);
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Click \"Send\" to submit the report to Audacity. This information is collected anonymously.")), wxSizerFlags().Border(wxALL));
}
mainLayout->AddSpacer(10);
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Problem details")), wxSizerFlags().Border(wxALL));
auto dumpTextCtrl = new wxTextCtrl(frame, wxID_ANY, dump, wxDefaultPosition, wxSize(500, 300), wxTE_RICH | wxTE_READONLY | wxTE_MULTILINE | wxTE_DONTWRAP);
dumpTextCtrl->SetFont(wxFont(wxFontInfo().Family(wxFONTFAMILY_TELETYPE)));
dumpTextCtrl->ShowPosition(0);//scroll to top
mainLayout->Add(dumpTextCtrl, wxSizerFlags().Border(wxALL).Expand());
if (onSend != nullptr)
{
mainLayout->AddSpacer(10);
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Comments")), wxSizerFlags().Border(wxALL));
mainLayout->Add(commentCtrl, wxSizerFlags().Border(wxALL).Expand());
}
mainLayout->Add(buttonsLayout, wxSizerFlags().Border(wxALL).Align(wxALIGN_RIGHT)); mainLayout->Add(buttonsLayout, wxSizerFlags().Border(wxALL).Align(wxALIGN_RIGHT));
frame->SetSizerAndFit(mainLayout); dialog->SetSizerAndFit(mainLayout);
frame->Show(true); dialog->Bind(wxEVT_CLOSE_WINDOW, [dialog](wxCloseEvent&) {
dialog->Destroy();
});
dialog->Show(true);
} }
} }
@ -386,7 +392,6 @@ void CrashReportApp::OnInitCmdLine(wxCmdLineParser& parser)
{ {
static const wxCmdLineEntryDesc cmdLineEntryDesc[] = static const wxCmdLineEntryDesc cmdLineEntryDesc[] =
{ {
{ wxCMD_LINE_SWITCH, "h", "help", "Display help on the command line parameters", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
{ wxCMD_LINE_SWITCH, "s", "silent", "Send without displaying the confirmation dialog" }, { wxCMD_LINE_SWITCH, "s", "silent", "Send without displaying the confirmation dialog" },
{ wxCMD_LINE_OPTION, "u", "url", "Crash report server URL", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_OPTION, "u", "url", "Crash report server URL", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
{ wxCMD_LINE_OPTION, "a", "args", "A set of arguments to send", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_OPTION, "a", "args", "A set of arguments to send", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },

View File

@ -45,7 +45,11 @@ if( ${_OPT}package_manual )
) \ ) \
") ")
if( "${CMAKE_GENERATOR}" MATCHES "Xcode" )
install( DIRECTORY "${out_dir}/${host}/" DESTINATION "${_APPDIR}/help/manual" )
elseif( "${CMAKE_GENERATOR}" MATCHES "Visual Studio*" )
install( DIRECTORY "${out_dir}/${host}/" DESTINATION "help/manual" ) install( DIRECTORY "${out_dir}/${host}/" DESTINATION "help/manual" )
endif()
endif() endif()
if( NOT CMAKE_SYSTEM_NAME MATCHES "Darwin" ) if( NOT CMAKE_SYSTEM_NAME MATCHES "Darwin" )

View File

@ -4822,7 +4822,7 @@ msgstr "Herzlich Willkommen zu Audacity-Version %s"
#: src/ProjectManager.cpp #: src/ProjectManager.cpp
#, c-format #, c-format
msgid "%sSave changes to %s?" msgid "%sSave changes to %s?"
msgstr "%sÄnderungen speichern nach %s?" msgstr "%sÄnderungen an %s speichern?"
#: src/ProjectManager.cpp #: src/ProjectManager.cpp
msgid "Save project before closing?" msgid "Save project before closing?"

View File

@ -22,17 +22,22 @@ fi
cmake --build build -j "${cpus}" --config "${AUDACITY_BUILD_TYPE}" cmake --build build -j "${cpus}" --config "${AUDACITY_BUILD_TYPE}"
BIN_OUTPUT_DIR=build/bin/${AUDACITY_BUILD_TYPE} BIN_OUTPUT_DIR=build/bin/${AUDACITY_BUILD_TYPE}
SHARED_OUTPUT_DIR=build/shared/${AUDACITY_BUILD_TYPE}
SYMBOLS_OUTPUT_DIR=debug SYMBOLS_OUTPUT_DIR=debug
mkdir ${SYMBOLS_OUTPUT_DIR} mkdir ${SYMBOLS_OUTPUT_DIR}
if [[ "${OSTYPE}" == msys* ]]; then # Windows if [[ "${OSTYPE}" == msys* ]]; then # Windows
# copy PDBs to debug folder... # copy PDBs to debug folder...
find ${BIN_OUTPUT_DIR} -name '*.pdb' | xargs -I % cp % ${SYMBOLS_OUTPUT_DIR} find ${BIN_OUTPUT_DIR} -name '*.pdb' | xargs -I % cp -v % ${SYMBOLS_OUTPUT_DIR}
find ${SHARED_OUTPUT_DIR} -name '*.pdb' | xargs -I % cp -v % ${SYMBOLS_OUTPUT_DIR}
find $(cygpath ${CONAN_USER_HOME}) -name '*.pdb' | xargs -I % cp -v % ${SYMBOLS_OUTPUT_DIR}
# and remove debug symbol files from the file tree before archieving # and remove debug symbol files from the file tree before archieving
find ${BIN_OUTPUT_DIR} -name '*.iobj' -o -name '*.ipdb' -o -name '*.pdb' -o -name '*.ilk' | xargs rm -f find ${BIN_OUTPUT_DIR} -name '*.iobj' -o -name '*.ipdb' -o -name '*.pdb' -o -name '*.ilk' | xargs rm -f
elif [[ "${OSTYPE}" == darwin* ]]; then # macOS elif [[ "${OSTYPE}" == darwin* ]]; then # macOS
find ${BIN_OUTPUT_DIR} -name '*.dSYM' | xargs -J % mv % ${SYMBOLS_OUTPUT_DIR} find ${BIN_OUTPUT_DIR} -name '*.dSYM' | xargs -J % mv % ${SYMBOLS_OUTPUT_DIR}
find ${SHARED_OUTPUT_DIR} -name '*.dSYM' | xargs -J % mv % ${SYMBOLS_OUTPUT_DIR}
find ${CONAN_USER_HOME}/dsyms -name '*.dSYM' | xargs -J % cp -R % ${SYMBOLS_OUTPUT_DIR}
else # Linux & others else # Linux & others
chmod +x scripts/ci/linux/split_debug_symbols.sh chmod +x scripts/ci/linux/split_debug_symbols.sh
find ${BIN_OUTPUT_DIR} -type f -executable -o -name '*.so' | xargs -n 1 scripts/ci/linux/split_debug_symbols.sh find ${BIN_OUTPUT_DIR} -type f -executable -o -name '*.so' | xargs -n 1 scripts/ci/linux/split_debug_symbols.sh

View File

@ -58,11 +58,32 @@ fi
if [[ ${GIT_BRANCH} == release* ]]; then if [[ ${GIT_BRANCH} == release* ]]; then
cmake_args+=( cmake_args+=(
-D audacity_package_manual=yes -D audacity_package_manual=yes
-D AUDACITY_BUILD_LEVEL=2
) )
fi fi
# Configure Audacity # Configure Audacity
cmake "${cmake_args[@]}" cmake "${cmake_args[@]}"
if [[ "${OSTYPE}" == msys* ]]; then # Windows
# On Windows, preserve PDB files before clearing the build cache
conanUnixPath=$(cygpath ${CONAN_USER_HOME})
pdbOutputPath="${conanUnixPath}/pdbs"
ls -la ${conanUnixPath}
mkdir -p "${pdbOutputPath}"
find "${conanUnixPath}/.conan" -name '*.pdb' '!' -name "vc14?.pdb" -type f | xargs -I % cp -v % ${pdbOutputPath}
elif [[ "${OSTYPE}" == darwin* ]]; then # macOS
# On macOS - find all the .dylib files and generate dSYMs from them
# in the same folder.
# dsymutil requires *.o files, so we need to generate files before clearing
# the build directories.
chmod +x scripts/ci/macos/generate_dsym.sh
scripts/ci/macos/generate_dsym.sh
fi
# Remove build directories and sources to reduce the cache size. # Remove build directories and sources to reduce the cache size.
conan remove "*" --src --builds --force conan remove "*" --src --builds --force

View File

@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -xe
function extractDSym()
{
local lib=$1
local libfile=$(basename $lib)
local libname="${libfile%.*}"
local targetdir=$2
local dsymfile=${targetdir}/${libname}.dSYM
if [[ -d "$dsymfile" ]]; then
echo "Skipping dSYM generation for $libfile: dSYM exists"
elif [[ ! -L "$lib" && "$lib" != "{}" && $lib != *"dSYM"* ]]; then
echo "Extracting dSYMs from $libfile to $dsymfile"
dsymutil "$lib" -o "$dsymfile"
fi
}
export -f extractDSym
mkdir -p "$CONAN_USER_HOME/dsyms"
find $CONAN_USER_HOME -name "*.dylib" | xargs -I {} bash -c "extractDSym \"{}\" \"$CONAN_USER_HOME/dsyms\""

View File

@ -6,10 +6,10 @@ set -euxo pipefail
cd build cd build
cpack -C "${AUDACITY_BUILD_TYPE}" --verbose
if [[ "${OSTYPE}" == msys* && ${GIT_BRANCH} == release* ]]; then # Windows if [[ "${OSTYPE}" == msys* && ${GIT_BRANCH} == release* ]]; then # Windows
cmake --build . --target innosetup --config "${AUDACITY_BUILD_TYPE}" cmake --build . --target innosetup --config "${AUDACITY_BUILD_TYPE}"
else
cpack -C "${AUDACITY_BUILD_TYPE}" --verbose
fi fi
# Remove the temporary directory # Remove the temporary directory

View File

@ -11,6 +11,6 @@ curl -sL https://sentry.io/get-cli/ | bash
SYMBOLS=$(find debug | xargs) SYMBOLS=$(find debug | xargs)
${INSTALL_DIR}/sentry-cli --auth-token ${SENTRY_AUTH_TOKEN} --url ${SENTRY_HOST} upload-dif \ ${INSTALL_DIR}/sentry-cli --auth-token ${SENTRY_AUTH_TOKEN} --url https://${SENTRY_HOST} upload-dif \
--org ${SENTRY_ORG_SLUG} \ --org ${SENTRY_ORG_SLUG} \
--project ${SENTRY_PROJECT_SLUG} ${SYMBOLS} --project ${SENTRY_PROJECT_SLUG} ${SYMBOLS}

View File

@ -714,7 +714,7 @@ void AColor::PreComputeGradient() {
gradient_pre[selected][1][i][2] = (unsigned char) (255 * b); gradient_pre[selected][1][i][2] = (unsigned char) (255 * b);
} }
// colorScheme 2: Grayscale // colorScheme 3: Inverse Grayscale
for (int i = 0; i < gradientSteps; i++) { for (int i = 0; i < gradientSteps; i++) {
float r, g, b; float r, g, b;
float value = float(i) / gradientSteps; float value = float(i) / gradientSteps;
@ -743,12 +743,12 @@ void AColor::PreComputeGradient() {
b = 1.0f; b = 1.0f;
break; break;
} }
gradient_pre[selected][2][i][0] = (unsigned char)(255 * r); gradient_pre[selected][3][i][0] = (unsigned char)(255 * r);
gradient_pre[selected][2][i][1] = (unsigned char)(255 * g); gradient_pre[selected][3][i][1] = (unsigned char)(255 * g);
gradient_pre[selected][2][i][2] = (unsigned char)(255 * b); gradient_pre[selected][3][i][2] = (unsigned char)(255 * b);
} }
// colorScheme 3: Inv. Grayscale (=Old grayscale) // colorScheme 2: Grayscale (=Old grayscale)
for (int i = 0; i<gradientSteps; i++) { for (int i = 0; i<gradientSteps; i++) {
float r, g, b; float r, g, b;
float value = float(i)/gradientSteps; float value = float(i)/gradientSteps;
@ -781,9 +781,9 @@ void AColor::PreComputeGradient() {
b = 1.0f; b = 1.0f;
break; break;
} }
gradient_pre[selected][3][i][0] = (unsigned char) (255 * r); gradient_pre[selected][2][i][0] = (unsigned char) (255 * r);
gradient_pre[selected][3][i][1] = (unsigned char) (255 * g); gradient_pre[selected][2][i][1] = (unsigned char) (255 * g);
gradient_pre[selected][3][i][2] = (unsigned char) (255 * b); gradient_pre[selected][2][i][2] = (unsigned char) (255 * b);
} }
} }
} }

View File

@ -74,6 +74,10 @@ hold information about one contributor to Audacity.
#define REV_IDENT (XO("No revision identifier was provided").Translation()) #define REV_IDENT (XO("No revision identifier was provided").Translation())
#endif #endif
#if defined(HAS_SENTRY_REPORTING) || defined(HAVE_UPDATES_CHECK) || defined(USE_BREAKPAD)
#define HAS_PRIVACY_POLICY
#endif
// To substitute into many other translatable strings // To substitute into many other translatable strings
static const auto ProgramName = static const auto ProgramName =
//XO("Audacity"); //XO("Audacity");
@ -129,7 +133,11 @@ void AboutDialog::CreateCreditsList()
// The Audacity Team: developers and support // The Audacity Team: developers and support
AddCredit(wxT("Anton Gerasimov"), developerFormat, roleTeamMember); AddCredit(wxT("Anton Gerasimov"), developerFormat, roleTeamMember);
AddCredit(wxT("Jouni Helminen"), roleTeamMember);
AddCredit(wxT("Peter Jonas"), developerFormat, roleTeamMember);
AddCredit(wxT("Martin Keary"), roleTeamMember);
AddCredit(wxT("Paul Licameli"), developerFormat, roleTeamMember); AddCredit(wxT("Paul Licameli"), developerFormat, roleTeamMember);
AddCredit(wxT("Anita Sudan"), roleTeamMember);
AddCredit(wxT("Vitaly Sverchinsky"), developerFormat, roleTeamMember); AddCredit(wxT("Vitaly Sverchinsky"), developerFormat, roleTeamMember);
AddCredit(wxT("Dmitry Vedenko"), developerFormat, roleTeamMember); AddCredit(wxT("Dmitry Vedenko"), developerFormat, roleTeamMember);
@ -825,7 +833,11 @@ void AboutDialog::PopulateInformationPage( ShuttleGui & S )
void AboutDialog::PopulateLicensePage( ShuttleGui & S ) void AboutDialog::PopulateLicensePage( ShuttleGui & S )
{ {
S.StartNotebookPage( XO("GPL License") ); #if defined(HAS_PRIVACY_POLICY)
S.StartNotebookPage(XC("Legal", "about dialog"));
#else
S.StartNotebookPage(XO("GPL License"));
#endif
S.StartVerticalLay(1); S.StartVerticalLay(1);
HtmlWindow *html = safenew LinkingHtmlWindow(S.GetParent(), -1, HtmlWindow *html = safenew LinkingHtmlWindow(S.GetParent(), -1,
wxDefaultPosition, wxDefaultPosition,
@ -838,7 +850,9 @@ void AboutDialog::PopulateLicensePage( ShuttleGui & S )
// better proportionally spaced. // better proportionally spaced.
// //
// The GPL is not to be translated.... // The GPL is not to be translated....
wxString PageText= FormatHtmlText(
constexpr auto GPL_TEXT =
wxT(" <center>GNU GENERAL PUBLIC LICENSE\n</center>") wxT(" <center>GNU GENERAL PUBLIC LICENSE\n</center>")
wxT(" <center>Version 2, June 1991\n</center>") wxT(" <center>Version 2, June 1991\n</center>")
wxT("<p><p>") wxT("<p><p>")
@ -1120,7 +1134,37 @@ wxT("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n
wxT("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n") wxT("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n")
wxT("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n") wxT("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n")
wxT("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n") wxT("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n")
wxT("POSSIBILITY OF SUCH DAMAGES.\n")); wxT("POSSIBILITY OF SUCH DAMAGES.\n");
#if defined(HAS_PRIVACY_POLICY)
/* i18n-hint: For "About Audacity...": Title for Privacy Policy section */
const auto privacyPolicyTitle = XC("PRIVACY POLICY", "about dialog");
/* i18n-hint: For "About Audacity...": Title of hyperlink to the privacy policy. This is an object of "See". */
const auto privacyPolicyURLText = XO("our Privacy Policy");
/* i18n-hint: %s will be replaced with "our Privacy Policy" */
const auto privacyPolicyText = XO(
"App update checking and error reporting require network access. "
"These features are optional. See %s "
"for more information.")
.Format(
Verbatim(
"[[https://www.audacityteam.org/about/desktop-privacy-notice/|%s]]")
.Format(privacyPolicyURLText));
const wxString privacyPolicyHTML = wxString(
wxT("<center>") +
privacyPolicyTitle.Translation() +
wxT("</center><p>") +
privacyPolicyText.Translation() +
wxT("</p><br/><br/>")
);
wxString PageText = FormatHtmlText(privacyPolicyHTML + GPL_TEXT);
#else
wxString PageText = FormatHtmlText(GPL_TEXT);
#endif
html->SetPage( PageText ); html->SetPage( PageText );

View File

@ -241,7 +241,7 @@ void PopulatePreferences()
wxYES_NO, NULL); wxYES_NO, NULL);
if (action == wxYES) // reset if (action == wxYES) // reset
{ {
gPrefs->DeleteAll(); ResetPreferences();
writeLang = true; writeLang = true;
} }
} }

View File

@ -1823,6 +1823,44 @@ int AudioIO::StartStream(const TransportTracks &tracks,
return mStreamToken; return mStreamToken;
} }
void AudioIO::DelayActions(bool recording)
{
mDelayingActions = recording;
}
bool AudioIO::DelayingActions() const
{
return mDelayingActions || (mPortStreamV19 && mNumCaptureChannels > 0);
}
void AudioIO::CallAfterRecording(PostRecordingAction action)
{
if (!action)
return;
{
std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
if (mPostRecordingAction) {
// Enqueue it, even if perhaps not still recording,
// but it wasn't cleared yet
mPostRecordingAction = [
prevAction = std::move(mPostRecordingAction),
nextAction = std::move(action)
]{ prevAction(); nextAction(); };
return;
}
else if (DelayingActions()) {
mPostRecordingAction = std::move(action);
return;
}
}
// Don't delay it except until idle time.
// (Recording might start between now and then, but won't go far before
// the action is done. So the system isn't bulletproof yet.)
wxTheApp->CallAfter(std::move(action));
}
bool AudioIO::AllocateBuffers( bool AudioIO::AllocateBuffers(
const AudioIOStartStreamOptions &options, const AudioIOStartStreamOptions &options,
const TransportTracks &tracks, double t0, double t1, double sampleRate, const TransportTracks &tracks, double t0, double t1, double sampleRate,
@ -2416,6 +2454,21 @@ void AudioIO::StopStream()
if (pListener && mNumCaptureChannels > 0) if (pListener && mNumCaptureChannels > 0)
pListener->OnAudioIOStopRecording(); pListener->OnAudioIOStopRecording();
wxTheApp->CallAfter([this]{
if (mPortStreamV19 && mNumCaptureChannels > 0)
// Recording was restarted between StopStream and idle time
// So the actions can keep waiting
return;
// In case some other thread was waiting on the mutex too:
std::this_thread::yield();
std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
if (mPostRecordingAction) {
mPostRecordingAction();
mPostRecordingAction = {};
}
DelayActions(false);
});
// //
// Only set token to 0 after we're totally finished with everything // Only set token to 0 after we're totally finished with everything
// //

View File

@ -18,9 +18,9 @@
#include "AudioIOBase.h" // to inherit #include "AudioIOBase.h" // to inherit
#include "PlaybackSchedule.h" // member variable #include "PlaybackSchedule.h" // member variable
#include <functional>
#include <memory> #include <memory>
#include <mutex>
#include <utility> #include <utility>
#include <wx/atomic.h> // member variable #include <wx/atomic.h> // member variable
@ -621,6 +621,12 @@ public:
* by the specified amount from where it is now */ * by the specified amount from where it is now */
void SeekStream(double seconds) { mSeek = seconds; } void SeekStream(double seconds) { mSeek = seconds; }
using PostRecordingAction = std::function<void()>;
//! Enqueue action for main thread idle time, not before the end of any recording in progress
/*! This may be called from non-main threads */
void CallAfterRecording(PostRecordingAction action);
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT #ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
bool IsScrubbing() const { return IsBusy() && mScrubState != 0; } bool IsScrubbing() const { return IsBusy() && mScrubState != 0; }
@ -733,15 +739,18 @@ public:
static void Init(); static void Init();
static void Deinit(); static void Deinit();
/*! For purposes of CallAfterRecording, treat time from now as if
recording (when argument is true) or not necessarily so (false) */
void DelayActions(bool recording);
private: private:
bool DelayingActions() const;
/** \brief Set the current VU meters - this should be done once after /** \brief Set the current VU meters - this should be done once after
* each call to StartStream currently */ * each call to StartStream currently */
void SetMeters(); void SetMeters();
/** \brief Opens the portaudio stream(s) used to do playback or recording /** \brief Opens the portaudio stream(s) used to do playback or recording
* (or both) through. * (or both) through.
* *
@ -787,6 +796,10 @@ private:
* *
* If bOnlyBuffers is specified, it only cleans up the buffers. */ * If bOnlyBuffers is specified, it only cleans up the buffers. */
void StartStreamCleanup(bool bOnlyBuffers = false); void StartStreamCleanup(bool bOnlyBuffers = false);
std::mutex mPostRecordingActionMutex;
PostRecordingAction mPostRecordingAction;
bool mDelayingActions{ false };
}; };
static constexpr unsigned ScrubPollInterval_ms = 50; static constexpr unsigned ScrubPollInterval_ms = 50;

View File

@ -1055,7 +1055,7 @@ list( APPEND DEFINES
__STDC_CONSTANT_MACROS __STDC_CONSTANT_MACROS
STRICT STRICT
> >
$<$<BOOL:${USE_UPDATE_CHECK}>: $<$<BOOL:${${_OPT}has_updates_check}>:
HAVE_UPDATES_CHECK HAVE_UPDATES_CHECK
> >
) )
@ -1375,6 +1375,7 @@ if( "${CMAKE_GENERATOR}" MATCHES "Xcode|Visual Studio*" )
USE_SOURCE_PERMISSIONS USE_SOURCE_PERMISSIONS
PATTERN "*.pdb" EXCLUDE PATTERN "*.pdb" EXCLUDE
PATTERN "*.ilk" EXCLUDE PATTERN "*.ilk" EXCLUDE
PATTERN "*.dSYM" EXCLUDE
) )
else() else()
if( CMAKE_SYSTEM_NAME MATCHES "Darwin" ) if( CMAKE_SYSTEM_NAME MATCHES "Darwin" )

View File

@ -886,6 +886,9 @@ void PluginManager::Load()
if (!registry.HasGroup(REGROOT)) if (!registry.HasGroup(REGROOT))
{ {
// Must start over // Must start over
// This DeleteAll affects pluginregistry.cfg only, not audacity.cfg
// That is, the memory of on/off states of effect (and generator,
// analyzer, and tool) plug-ins
registry.DeleteAll(); registry.DeleteAll();
registry.Flush(); registry.Flush();
return; return;
@ -1223,7 +1226,7 @@ void PluginManager::Save()
{}, {}, FileNames::PluginRegistry()); {}, {}, FileNames::PluginRegistry());
auto &registry = *pRegistry; auto &registry = *pRegistry;
// Clear it out // Clear pluginregistry.cfg (not audacity.cfg)
registry.DeleteAll(); registry.DeleteAll();
// Write the version string // Write the version string

View File

@ -63,6 +63,9 @@
#include "MemoryX.h" #include "MemoryX.h"
#include <memory> #include <memory>
BoolSetting DefaultUpdatesCheckingFlag{
L"/Update/DefaultUpdatesChecking", true };
std::unique_ptr<FileConfig> ugPrefs {}; std::unique_ptr<FileConfig> ugPrefs {};
FileConfig *gPrefs = nullptr; FileConfig *gPrefs = nullptr;
@ -179,6 +182,25 @@ void InitPreferences( std::unique_ptr<FileConfig> uPrefs )
wxConfigBase::Set(gPrefs); wxConfigBase::Set(gPrefs);
} }
void ResetPreferences()
{
// Future: make this a static registry table, so the settings objects
// don't need to be defined in this source code file to avoid dependency
// cycles
std::pair<BoolSetting &, bool> stickyBoolSettings[] {
{DefaultUpdatesCheckingFlag, 0},
// ... others?
};
for (auto &pair : stickyBoolSettings)
pair.second = pair.first.Read();
bool savedValue = DefaultUpdatesCheckingFlag.Read();
gPrefs->DeleteAll();
for (auto &pair : stickyBoolSettings)
pair.first.Write(pair.second);
}
void FinishPreferences() void FinishPreferences()
{ {
if (gPrefs) { if (gPrefs) {

View File

@ -48,6 +48,12 @@
class wxFileName; class wxFileName;
void InitPreferences( std::unique_ptr<FileConfig> uPrefs ); void InitPreferences( std::unique_ptr<FileConfig> uPrefs );
//! Call this to reset preferences to an (almost)-"new" default state
/*!
There is at least one exception to that: user preferences we want to make
more "sticky." Notably, whether automatic update checking is preferred.
*/
void ResetPreferences();
void FinishPreferences(); void FinishPreferences();
extern AUDACITY_DLL_API FileConfig *gPrefs; extern AUDACITY_DLL_API FileConfig *gPrefs;
@ -423,4 +429,7 @@ struct AUDACITY_DLL_API PreferenceInitializer {
static void ReinitializeAll(); static void ReinitializeAll();
}; };
// Special extra-sticky settings
extern AUDACITY_DLL_API BoolSetting DefaultUpdatesCheckingFlag;
#endif #endif

View File

@ -40,6 +40,7 @@
#include <wx/timer.h> #include <wx/timer.h>
#include <wx/dynlib.h> //<! For windows.h #include <wx/dynlib.h> //<! For windows.h
#include "AudioIO.h"
#include "ShuttleGui.h" #include "ShuttleGui.h"
#include "ProjectAudioManager.h" #include "ProjectAudioManager.h"
#include "ProjectFileIO.h" #include "ProjectFileIO.h"
@ -481,6 +482,11 @@ int TimerRecordDialog::RunWaitDialog()
{ {
auto updateResult = ProgressResult::Success; auto updateResult = ProgressResult::Success;
const auto gAudioIO = AudioIO::Get();
gAudioIO->DelayActions(true);
{
auto cleanup = finally([gAudioIO]{ gAudioIO->DelayActions(false); });
if (m_DateTime_Start > wxDateTime::UNow()) if (m_DateTime_Start > wxDateTime::UNow())
updateResult = this->WaitForStart(); updateResult = this->WaitForStart();
@ -535,6 +541,7 @@ int TimerRecordDialog::RunWaitDialog()
bIsRecording = (wxDateTime::UNow() <= m_DateTime_End); // Call UNow() again for extra accuracy... bIsRecording = (wxDateTime::UNow() <= m_DateTime_End); // Call UNow() again for extra accuracy...
} }
} }
}
// Must do this AFTER the timer project dialog has been deleted to ensure the application // Must do this AFTER the timer project dialog has been deleted to ensure the application
// responds to the AUDIOIO events...see not about bug #334 in the ProgressDialog constructor. // responds to the AUDIOIO events...see not about bug #334 in the ProgressDialog constructor.

View File

@ -648,6 +648,7 @@ wxString EffectManager::GetPreset(const PluginID & ID, const wxString & params,
return preset; return preset;
} }
// This cleans a config "file" backed by a string in memory.
eap.DeleteAll(); eap.DeleteAll();
eap.Write(wxT("Use Preset"), preset); eap.Write(wxT("Use Preset"), preset);

View File

@ -106,15 +106,38 @@
return intgr ; return intgr ;
} }
#elif (defined (WIN32) || defined (_WIN32)) && defined(_M_3X64) #elif (defined (WIN32) || defined (_WIN32)) && defined(_M_X64)
#include <math.h> #include <math.h>
#include <immintrin.h> #include <immintrin.h>
#include <emmintrin.h>
__inline long int #ifdef _MSC_VER
lrintf (float flt) #pragma function(lrint, lrintf)
#endif
__inline
long int lrint(double flt)
{ {
return _mm_cvt_ss2si(_mm_set_ss(flt)); return _mm_cvtsd_si32(_mm_set_sd(flt));
}
__inline
long int lrintf (float flt)
{
return _mm_cvtss_si32(_mm_set_ss(flt));
}
__inline
long long int llrint(double flt)
{
return _mm_cvtsd_si64(_mm_set_sd(flt));
}
__inline
long long int llrintf(float flt)
{
return _mm_cvtss_si64(_mm_set_ss(flt));
} }
#elif (HAVE_LRINT && HAVE_LRINTF) #elif (HAVE_LRINT && HAVE_LRINTF)

View File

@ -393,7 +393,7 @@ void OnResetConfig(const CommandContext &context)
menuManager.mLastAnalyzer = ""; menuManager.mLastAnalyzer = "";
menuManager.mLastTool = ""; menuManager.mLastTool = "";
gPrefs->DeleteAll(); ResetPreferences();
// Directory will be reset on next restart. // Directory will be reset on next restart.
FileNames::UpdateDefaultPath(FileNames::Operation::Temp, TempDirectory::DefaultTempDir()); FileNames::UpdateDefaultPath(FileNames::Operation::Temp, TempDirectory::DefaultTempDir());

View File

@ -70,8 +70,7 @@ void ApplicationPrefs::PopulateOrExchange(ShuttleGui & S)
S.StartStatic(XO("Update Audacity")); S.StartStatic(XO("Update Audacity"));
{ {
S.TieCheckBox(XO("&Check for Updates"), S.TieCheckBox(XO("&Check for Updates"), DefaultUpdatesCheckingFlag);
UpdatesCheckingSettings::DefaultUpdatesCheckingFlag);
} }
S.EndStatic(); S.EndStatic();
S.EndScroller(); S.EndScroller();

View File

@ -182,7 +182,7 @@ void SpectrogramSettings::ColorSchemeEnumSetting::Migrate(wxString &value)
// Migrate old grayscale option to Color scheme choice // Migrate old grayscale option to Color scheme choice
bool isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0); bool isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
if (isGrayscale && !gPrefs->Read(wxT("/Spectrum/ColorScheme"), &value)) { if (isGrayscale && !gPrefs->Read(wxT("/Spectrum/ColorScheme"), &value)) {
value = GetColorSchemeNames().at(csInvGrayscale).Internal(); value = GetColorSchemeNames().at(csGrayscale).Internal();
Write(value); Write(value);
gPrefs->Flush(); gPrefs->Flush();
} }

View File

@ -56,23 +56,41 @@ bool UpdateDataParser::HandleXMLTag(const wxChar* tag, const wxChar** attrs)
return true; return true;
} }
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kWindowsTag]) == 0) const wxPlatformInfo& info = wxPlatformInfo::Get();
constexpr bool is32Bit = sizeof(void*) == 4;
constexpr bool is64Bit = sizeof(void*) == 8;
if (is32Bit)
{ {
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_WINDOWS) if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kWin32Tag]) == 0)
{
if (info.GetOperatingSystemId() & wxOS_WINDOWS)
mXmlParsingState = XmlParsedTags::kOsTag; mXmlParsingState = XmlParsedTags::kOsTag;
return true; return true;
} }
}
if (is64Bit)
{
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kWin64Tag]) == 0)
{
if (info.GetOperatingSystemId() & wxOS_WINDOWS)
mXmlParsingState = XmlParsedTags::kOsTag;
return true;
}
}
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kMacosTag]) == 0) if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kMacosTag]) == 0)
{ {
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_MAC) if (info.GetOperatingSystemId() & wxOS_MAC)
mXmlParsingState = XmlParsedTags::kOsTag; mXmlParsingState = XmlParsedTags::kOsTag;
return true; return true;
} }
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kLinuxTag]) == 0) if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kLinuxTag]) == 0)
{ {
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_UNIX_LINUX) if (info.GetOperatingSystemId() & wxOS_UNIX_LINUX)
mXmlParsingState = XmlParsedTags::kOsTag; mXmlParsingState = XmlParsedTags::kOsTag;
return true; return true;
} }

View File

@ -36,7 +36,8 @@ private:
kUpdateTag, kUpdateTag,
kDescriptionTag, kDescriptionTag,
kOsTag, kOsTag,
kWindowsTag, kWin32Tag,
kWin64Tag,
kMacosTag, kMacosTag,
kLinuxTag, kLinuxTag,
kVersionTag, kVersionTag,
@ -48,7 +49,8 @@ private:
{ XmlParsedTags::kUpdateTag, wxT("Updates") }, { XmlParsedTags::kUpdateTag, wxT("Updates") },
{ XmlParsedTags::kDescriptionTag, wxT("Description") }, { XmlParsedTags::kDescriptionTag, wxT("Description") },
{ XmlParsedTags::kOsTag, wxT("OS") }, { XmlParsedTags::kOsTag, wxT("OS") },
{ XmlParsedTags::kWindowsTag, wxT("Windows") }, { XmlParsedTags::kWin32Tag, wxT("Win32") },
{ XmlParsedTags::kWin64Tag, wxT("Win64") },
{ XmlParsedTags::kMacosTag, wxT("Macos") }, { XmlParsedTags::kMacosTag, wxT("Macos") },
{ XmlParsedTags::kLinuxTag, wxT("Linux") }, { XmlParsedTags::kLinuxTag, wxT("Linux") },
{ XmlParsedTags::kVersionTag, wxT("Version") }, { XmlParsedTags::kVersionTag, wxT("Version") },

View File

@ -10,6 +10,7 @@
#include "UpdateManager.h" #include "UpdateManager.h"
#include "UpdatePopupDialog.h" #include "UpdatePopupDialog.h"
#include "AudioIO.h"
#include "NetworkManager.h" #include "NetworkManager.h"
#include "IResponse.h" #include "IResponse.h"
#include "Request.h" #include "Request.h"
@ -21,26 +22,23 @@
#include <wx/frame.h> #include <wx/frame.h>
#include <mutex> #include <mutex>
#include <cstdint>
BoolSetting UpdatesCheckingSettings::DefaultUpdatesCheckingFlag{
L"/Update/DefaultUpdatesChecking", true };
static const char* prefsUpdateScheduledTime = "/Update/UpdateScheduledTime"; static const char* prefsUpdateScheduledTime = "/Update/UpdateScheduledTime";
using Clock = std::chrono::system_clock;
using TimePoint = Clock::time_point;
using Duration = TimePoint::duration;
constexpr Duration updatesCheckInterval = std::chrono::hours(12);
enum { ID_TIMER = wxID_HIGHEST + 1 }; enum { ID_TIMER = wxID_HIGHEST + 1 };
BEGIN_EVENT_TABLE(UpdateManager, wxEvtHandler) BEGIN_EVENT_TABLE(UpdateManager, wxEvtHandler)
EVT_TIMER(ID_TIMER, UpdateManager::OnTimer) EVT_TIMER(ID_TIMER, UpdateManager::OnTimer)
END_EVENT_TABLE() END_EVENT_TABLE()
UpdateManager::UpdateManager()
: mUpdateCheckingInterval(
std::chrono::milliseconds(std::chrono::hours(12)).count())
{}
UpdateManager::~UpdateManager()
{}
UpdateManager& UpdateManager::GetInstance() UpdateManager& UpdateManager::GetInstance()
{ {
static UpdateManager updateManager; static UpdateManager updateManager;
@ -64,38 +62,48 @@ VersionPatch UpdateManager::GetVersionPatch() const
return mVersionPatch; return mVersionPatch;
} }
void UpdateManager::GetUpdates() void UpdateManager::GetUpdates(bool ignoreNetworkErrors)
{ {
const audacity::network_manager::Request request("https://updates.audacityteam.org/feed/latest.xml"); const audacity::network_manager::Request request("https://updates.audacityteam.org/feed/latest.xml");
auto response = audacity::network_manager::NetworkManager::GetInstance().doGet(request); auto response = audacity::network_manager::NetworkManager::GetInstance().doGet(request);
response->setRequestFinishedCallback([response, this](audacity::network_manager::IResponse*) { response->setRequestFinishedCallback([response, ignoreNetworkErrors, this](audacity::network_manager::IResponse*) {
auto gAudioIO = AudioIO::Get();
if (response->getError() != audacity::network_manager::NetworkError::NoError) if (response->getError() != audacity::network_manager::NetworkError::NoError)
{ {
wxTheApp->CallAfter([] {ShowExceptionDialog(nullptr, if (!ignoreNetworkErrors)
XC("Error checking for update", "update dialog"), {
XC("Unable to connect to Audacity update server.", "update dialog"), gAudioIO->CallAfterRecording([] {
ShowExceptionDialog(
nullptr, XC("Error checking for update", "update dialog"),
XC("Unable to connect to Audacity update server.",
"update dialog"),
wxString()); wxString());
}); });
}
return; return;
} }
if (!mUpdateDataParser.Parse(response->readAll<VersionPatch::UpdateDataFormat>(), &mVersionPatch)) if (!mUpdateDataParser.Parse(response->readAll<VersionPatch::UpdateDataFormat>(), &mVersionPatch))
{ {
wxTheApp->CallAfter([] {ShowExceptionDialog(nullptr, if (!ignoreNetworkErrors)
XC("Error checking for update", "update dialog"), {
gAudioIO->CallAfterRecording([] {
ShowExceptionDialog(
nullptr, XC("Error checking for update", "update dialog"),
XC("Update data was corrupted.", "update dialog"), XC("Update data was corrupted.", "update dialog"),
wxString()); wxString());
}); });
}
return; return;
} }
if (mVersionPatch.version > CurrentBuildVersion()) if (mVersionPatch.version > CurrentBuildVersion())
{ {
wxTheApp->CallAfter([this] { gAudioIO->CallAfterRecording([this] {
UpdatePopupDialog dlg(nullptr, mVersionPatch); UpdatePopupDialog dlg(nullptr, mVersionPatch);
const int code = dlg.ShowModal(); const int code = dlg.ShowModal();
@ -116,34 +124,49 @@ void UpdateManager::GetUpdates()
void UpdateManager::OnTimer(wxTimerEvent& WXUNUSED(event)) void UpdateManager::OnTimer(wxTimerEvent& WXUNUSED(event))
{ {
bool updatesCheckingEnabled = UpdatesCheckingSettings::DefaultUpdatesCheckingFlag.Read(); bool updatesCheckingEnabled = DefaultUpdatesCheckingFlag.Read();
if (updatesCheckingEnabled && IsTimeForUpdatesChecking()) if (updatesCheckingEnabled && IsTimeForUpdatesChecking())
GetUpdates(); GetUpdates(true);
mTimer.StartOnce(mUpdateCheckingInterval); mTimer.StartOnce(std::chrono::duration_cast<std::chrono::milliseconds>(
updatesCheckInterval)
.count());
} }
bool UpdateManager::IsTimeForUpdatesChecking() bool UpdateManager::IsTimeForUpdatesChecking()
{ {
long long nextUpdatesCheckingTime = std::stoll( // We use atoll here, so there is no need to handle the exception,
gPrefs->Read(prefsUpdateScheduledTime, "0").ToStdString()); // if prefsUpdateScheduledTime is corrupted.
// atoll will return 0 on failure, which suits us well.
const TimePoint nextUpdatesCheckingTime(std::chrono::milliseconds(
atoll(gPrefs->Read(prefsUpdateScheduledTime, "0").c_str())));
// Get current time in milliseconds // Get current time
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>( const TimePoint currentTime = Clock::now();
std::chrono::system_clock::now());
auto currentTimeInMillisec = std::chrono::duration_cast<std::chrono::milliseconds>(
now_ms.time_since_epoch()).count();
// If next update time 0 or less then current time -> show update dialog, // If next update time 0 or less then current time -> show update dialog,
// else this condition allow us to avoid from duplicating update notifications. // else this condition allow us to avoid from duplicating update notifications.
if (nextUpdatesCheckingTime < currentTimeInMillisec) if (nextUpdatesCheckingTime < currentTime)
{ {
nextUpdatesCheckingTime = currentTimeInMillisec + mUpdateCheckingInterval;
gPrefs->Write(prefsUpdateScheduledTime, // Round down the nextUpdatesChecking time to a day.
wxString(std::to_string(nextUpdatesCheckingTime))); // This is required to ensure, that update is
// checked daily
using DayDuration =
std::chrono::duration<int32_t, std::ratio<60 * 60 * 24>>;
const auto postponeUpdateUntil =
std::chrono::time_point_cast<DayDuration>(
currentTime) + DayDuration(1);
const std::chrono::milliseconds postponeUpdateUntilMS(
postponeUpdateUntil.time_since_epoch());
gPrefs->Write(
prefsUpdateScheduledTime,
wxString(std::to_string(postponeUpdateUntilMS.count())));
gPrefs->Flush(); gPrefs->Flush();
return true; return true;

View File

@ -18,10 +18,6 @@
#include <wx/event.h> #include <wx/event.h>
#include <wx/timer.h> #include <wx/timer.h>
namespace UpdatesCheckingSettings {
extern AUDACITY_DLL_API BoolSetting DefaultUpdatesCheckingFlag;
}
/// A class that managing of updates. /// A class that managing of updates.
/** /**
Opt-in request and show update dialog by the scheduled time. Opt-in request and show update dialog by the scheduled time.
@ -31,13 +27,12 @@ namespace UpdatesCheckingSettings {
class UpdateManager final : public wxEvtHandler class UpdateManager final : public wxEvtHandler
{ {
public: public:
UpdateManager(); UpdateManager() = default;
~UpdateManager();
static UpdateManager& GetInstance(); static UpdateManager& GetInstance();
static void Start(); static void Start();
void GetUpdates(); void GetUpdates(bool ignoreNetworkErrors);
VersionPatch GetVersionPatch() const; VersionPatch GetVersionPatch() const;
@ -46,7 +41,6 @@ private:
VersionPatch mVersionPatch; VersionPatch mVersionPatch;
wxTimer mTimer; wxTimer mTimer;
const int mUpdateCheckingInterval;
void OnTimer(wxTimerEvent& event); void OnTimer(wxTimerEvent& event);

View File

@ -45,7 +45,7 @@ UpdatePopupDialog::UpdatePopupDialog (wxWindow* parent, const VersionPatch& vers
S.Id (DontShowID).AddCheckBox ( S.Id (DontShowID).AddCheckBox (
XO ("Don't show this again at start up"), XO ("Don't show this again at start up"),
!UpdatesCheckingSettings::DefaultUpdatesCheckingFlag.Read()); !DefaultUpdatesCheckingFlag.Read());
S.Prop(1).AddSpace(1, 0, 1); S.Prop(1).AddSpace(1, 0, 1);
@ -80,7 +80,7 @@ void UpdatePopupDialog::OnSkip (wxCommandEvent&)
void UpdatePopupDialog::OnDontShow (wxCommandEvent& event) void UpdatePopupDialog::OnDontShow (wxCommandEvent& event)
{ {
UpdatesCheckingSettings::DefaultUpdatesCheckingFlag.Write(!event.IsChecked()); DefaultUpdatesCheckingFlag.Write(!event.IsChecked());
} }
HtmlWindow* UpdatePopupDialog::AddHtmlContent (wxWindow* parent) HtmlWindow* UpdatePopupDialog::AddHtmlContent (wxWindow* parent)

View File

@ -12,10 +12,10 @@
if( BUILDING_64_BIT ) if( BUILDING_64_BIT )
set( INSTALLER_SUFFIX "x64" ) set( INSTALLER_SUFFIX "x64" )
set( INSTALLER_X64_MODE "ArchitecturesInstallIn64BitMode=x64") set( INSTALLER_X64_MODE "ArchitecturesInstallIn64BitMode=x64" )
else() else()
set( INSTALLER_SUFFIX "x86" ) set( INSTALLER_SUFFIX "x86" )
set( INSTALLER_X64_MODE "ArchitecturesInstallIn64BitMode=x64") set( INSTALLER_X64_MODE "" )
endif() endif()
if( SIGN ) if( SIGN )

View File

@ -96,7 +96,7 @@ Source: ".\FirstTimeModel.ini"; DestDir: "{app}"; DestName: "FirstTime.ini"; Per
Source: "Additional\README.txt"; DestDir: "{app}"; Flags: ignoreversion Source: "Additional\README.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "Additional\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion Source: "Additional\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
Source: "{#AppExe}"; DestDir: "{app}"; Flags: ignoreversion Source: "Package\*.exe"; DestDir: "{app}"; Flags: ignoreversion
; Manual, which should be got from the manual wiki using ..\scripts\mw2html_audacity\wiki2htm.bat ; Manual, which should be got from the manual wiki using ..\scripts\mw2html_audacity\wiki2htm.bat
@MANUAL@ @MANUAL@