30#include <wx/wxcrtvararg.h>
32#include <wx/evtloop.h>
34#include <wx/docview.h>
38#include <wx/snglinst.h>
40#include <wx/stdpaths.h>
42#include <wx/fontmap.h>
48#include <wx/filename.h>
66#include <wx/msw/registry.h>
122#if defined(HAVE_UPDATES_CHECK)
130#ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS
142#if defined(USE_BREAKPAD)
144#elif defined(USE_CRASHPAD)
148#ifdef EXPERIMENTAL_SCOREALIGN
156 static char*THIS_FILE= __FILE__;
157 #define new new(_NORMAL_BLOCK, THIS_FILE, __LINE__)
163#ifdef EXPERIMENTAL_DA
164#include "../images/DarkAudacityLogoWithName.xpm"
166#include "../images/AudacityLogoWithName.xpm"
171#ifdef HAS_CUSTOM_URL_HANDLING
176static wxString urlPrefix =
wxT(
"url:");
186static void wxOnAssert(
const wxChar *fileName,
int lineNumber,
const wxChar *msg)
189 wxPrintf(
"ASSERTION FAILED: %s\n%s: %d\n", (
const char *)wxString(msg).mb_str(), (
const char *)wxString(fileName).mb_str(), lineNumber);
191 wxPrintf(
"ASSERTION FAILED!\n%s: %d\n", (
const char *)wxString(fileName).mb_str(), lineNumber);
207 bool resetPrefs =
false;
208 wxString langCode =
gPrefs->Read(
wxT(
"/Locale/Language"), wxEmptyString);
209 bool writeLang =
false;
213 wxT(
"FirstTime.ini"));
216 const wxString fullPath{
fn.GetFullPath()};
220 wxCONFIG_USE_LOCAL_FILE);
224 if (ini.Read(
wxT(
"/FromInno/Language"), &lang) && !lang.empty())
232 langCode.Replace(
wxT(
"0"),
wxT(
"@"));
235 ini.Read(
wxT(
"/FromInno/ResetPrefs"), &resetPrefs,
false);
237 bool gone = wxRemoveFile(fullPath);
241 XO(
"Failed to remove %s").
Format(fullPath),
247 if (langCode.empty())
258"Reset Preferences?\n\nThis is a one-time question, after an 'install' where you asked to have the Preferences reset.");
261 XO(
"Reset Audacity Preferences"),
273 gPrefs->Write(
wxT(
"/Locale/Language"), langCode);
280 bool newPrefsInitialized =
false;
281 gPrefs->Read(
wxT(
"/NewPrefsInitialized"), &newPrefsInitialized,
false);
282 if (newPrefsInitialized) {
295 int vMajor =
gPrefs->Read(
wxT(
"/Version/Major"), (
long) 0);
296 int vMinor =
gPrefs->Read(
wxT(
"/Version/Minor"), (
long) 0);
297 int vMicro =
gPrefs->Read(
wxT(
"/Version/Micro"), (
long) 0);
306 (vMajor == 1 && vMinor < 3) ||
307 (vMajor == 1 && vMinor == 3 && vMicro < 13)) {
311 if (
gPrefs->Exists(
wxT(
"/GUI/ToolBars/Device")))
317 if (
gPrefs->Exists(
wxT(
"/GUI/ToolBars/Mixer"))) {
319 gPrefs->Write(
wxT(
"/GUI/ToolBars/Mixer/W"), -1);
326 if (
gPrefs->Exists(
wxT(
"/GUI/ToolBars/Meter")) &&
327 !
gPrefs->Exists(
wxT(
"/GUI/ToolBars/CombinedMeter"))) {
330 long dock, order, show, x, y, w, h;
331 gPrefs->Read(
wxT(
"/GUI/ToolBars/Meter/Dock"), &dock, -1);
332 gPrefs->Read(
wxT(
"/GUI/ToolBars/Meter/Order"), &order, -1);
333 gPrefs->Read(
wxT(
"/GUI/ToolBars/Meter/Show"), &show, -1);
334 gPrefs->Read(
wxT(
"/GUI/ToolBars/Meter/X"), &x, -1);
335 gPrefs->Read(
wxT(
"/GUI/ToolBars/Meter/Y"), &y, -1);
336 gPrefs->Read(
wxT(
"/GUI/ToolBars/Meter/W"), &w, -1);
337 gPrefs->Read(
wxT(
"/GUI/ToolBars/Meter/H"), &h, -1);
349 if (
gPrefs->Read(bar +
wxT(
"/Order"), &o) && o >= order) {
350 gPrefs->Write(bar +
wxT(
"/Order"), o + 2);
361 gPrefs->Write(
wxT(
"/GUI/ToolBars/RecordMeter/Dock"), dock);
362 gPrefs->Write(
wxT(
"/GUI/ToolBars/RecordMeter/Order"), order);
363 gPrefs->Write(
wxT(
"/GUI/ToolBars/RecordMeter/Show"), show);
364 gPrefs->Write(
wxT(
"/GUI/ToolBars/RecordMeter/X"), -1);
365 gPrefs->Write(
wxT(
"/GUI/ToolBars/RecordMeter/Y"), -1);
366 gPrefs->Write(
wxT(
"/GUI/ToolBars/RecordMeter/W"), w);
367 gPrefs->Write(
wxT(
"/GUI/ToolBars/RecordMeter/H"), h);
368 gPrefs->Write(
wxT(
"/GUI/ToolBars/PlayMeter/Dock"), dock);
369 gPrefs->Write(
wxT(
"/GUI/ToolBars/PlayMeter/Order"), order + 1);
370 gPrefs->Write(
wxT(
"/GUI/ToolBars/PlayMeter/Show"), show);
371 gPrefs->Write(
wxT(
"/GUI/ToolBars/PlayMeter/X"), -1);
372 gPrefs->Write(
wxT(
"/GUI/ToolBars/PlayMeter/Y"), -1);
373 gPrefs->Write(
wxT(
"/GUI/ToolBars/PlayMeter/W"), w);
374 gPrefs->Write(
wxT(
"/GUI/ToolBars/PlayMeter/H"), h);
377 gPrefs->Write(
wxT(
"/GUI/ToolBars/Meter/Dock"), -1);
381 if ((0<vMajor && vMajor < 2) ||
382 (vMajor == 2 && vMinor < 2))
384 gPrefs->Write(
wxT(
"/GUI/Shortcuts/FullDefaults"),1);
388 if ((0<vMajor && vMajor < 2) ||
389 (vMajor == 2 && vMinor < 4))
391 gPrefs->Write(
wxT(
"/GUI/Toolbars/Selection/W"),
"");
392 gPrefs->Write(
wxT(
"/GUI/Toolbars/SpectralSelection/W"),
"");
393 gPrefs->Write(
wxT(
"/GUI/Toolbars/Time/X"),-1);
394 gPrefs->Write(
wxT(
"/GUI/Toolbars/Time/Y"),-1);
395 gPrefs->Write(
wxT(
"/GUI/Toolbars/Time/H"),55);
396 gPrefs->Write(
wxT(
"/GUI/Toolbars/Time/W"),251);
397 gPrefs->Write(
wxT(
"/GUI/Toolbars/Time/DockV2"),2);
398 gPrefs->Write(
wxT(
"/GUI/Toolbars/Time/Dock"),2);
399 gPrefs->Write(
wxT(
"/GUI/Toolbars/Time/Path"),
"0,1");
400 gPrefs->Write(
wxT(
"/GUI/Toolbars/Time/Show"),1);
403 if (std::pair{ vMajor, vMinor } < std::pair{ 3, 1 } ) {
405 gPrefs->Write(
wxT(
"/GUI/Toolbars/Control/W"), -1);
408 if(std::pair{vMajor, vMinor} < std::pair{3, 2})
414 if(
gPrefs->Exists(
"/GUI/ShowSplashScreen"))
416 if(
gPrefs->Exists(
"/GUI/Help"))
420 if(std::tuple{ vMajor, vMinor, vMicro } < std::tuple{ 3, 2, 3 })
423 if(
gPrefs->Exists(
"/GUI/ToolBars/Share Audio/W"))
428 if (std::pair { vMajor, vMinor } < std::pair { 3, 3 })
430 if (
gPrefs->Exists(
wxT(
"/GUI/ToolBars")))
435 gPrefs->Write(
wxT(
"/Version/Major"), AUDACITY_VERSION);
436 gPrefs->Write(
wxT(
"/Version/Minor"), AUDACITY_RELEASE);
437 gPrefs->Write(
wxT(
"/Version/Micro"), AUDACITY_REVISION);
444#if defined(USE_BREAKPAD) || defined(USE_CRASHPAD)
445 wxFileName databasePath;
447 databasePath.AppendDir(
"crashreports");
448 databasePath.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
450 if(databasePath.DirExists())
452 const auto sentryRelease = wxString::Format(
453 "[email protected]%d.%d.%d", AUDACITY_VERSION, AUDACITY_RELEASE, AUDACITY_REVISION);
454#if defined(USE_BREAKPAD)
458 #if defined(CRASH_REPORT_URL)
462 {
"version", wxString(AUDACITY_VERSION_STRING).ToUTF8().data() },
463 {
"sentry[release]", sentryRelease.ToUTF8().data() }
466#elif defined(USE_CRASHPAD)
470 const wxFileName crashpadHandlerPath(executableDir, CRASHPAD_HANDLER_NAME);
471 const wxFileName crashreporterPath(executableDir, CRASHREPORTER_NAME);
472 const wxFileName metricsDir = databasePath;
473 std::vector<std::string> arguments = {
474 wxString::Format(
"--crashreporter-path=%s", crashreporterPath.GetFullPath()).ToUTF8().data(),
475#if defined(CRASH_REPORT_URL)
477 "--crashreporter-argument=-u=%s",
478 CRASH_REPORT_URL).ToUTF8().data(),
480 "--crashreporter-argument=-a=version=\"%s\",sentry[release]=\"%s\"",
481 AUDACITY_VERSION_STRING,
482 sentryRelease).ToUTF8().data()
492 catch (std::exception& e)
494 wxLogError(
"Crashpad init error: %s", e.what());
498#elif !defined(_DEBUG)
499#if defined(HAS_CRASH_REPORT)
500#if defined(wxUSE_ON_FATAL_EXCEPTION) && wxUSE_ON_FATAL_EXCEPTION
501 wxHandleFatalExceptions();
541 wxTheApp->SetExitOnFrameDelete(
true);
573#ifdef EXPERIMENTAL_SCOREALIGN
574 CloseScoreAlignDialog();
580 #if !defined(__WXMAC__)
594 logger->SaveLog(logFile.GetFullPath());
598 std::unique_ptr<wxLog>{ wxLog::SetActiveTarget(NULL) };
611#if defined(__WXGTK__) && defined(HAVE_GTK)
631#include <glib-object.h>
633typedef struct _GnomeProgram GnomeProgram;
634typedef struct _GnomeModuleInfo GnomeModuleInfo;
635typedef struct _GnomeClient GnomeClient;
647 GNOME_INTERACT_ERRORS,
657typedef GnomeProgram * (*_gnome_program_init_fn)(
const char *,
659 const GnomeModuleInfo *,
664typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
665typedef GnomeClient * (*_gnome_master_client_fn)(void);
666typedef void (*GnomeInteractFunction)(GnomeClient *,
670typedef void (*_gnome_client_request_interaction_fn)(GnomeClient *,
672 GnomeInteractFunction,
674typedef void (*_gnome_interaction_key_return_fn)(gint, gboolean);
676static _gnome_client_request_interaction_fn gnome_client_request_interaction;
677static _gnome_interaction_key_return_fn gnome_interaction_key_return;
679static void interact_cb(GnomeClient * ,
684 wxCloseEvent e(wxEVT_QUERY_END_SESSION, wxID_ANY);
690 gnome_interaction_key_return(
key, e.GetVeto());
693static gboolean save_yourself_cb(GnomeClient *client,
697 GnomeInteractStyle interact,
701 if (!shutdown || interact != GNOME_INTERACT_ANY) {
709 gnome_client_request_interaction(client,
722 mArgv[0].reset(strdup(
"Audacity"));
724 mGnomeui = dlopen(
"libgnomeui-2.so.0", RTLD_NOW);
729 mGnome = dlopen(
"libgnome-2.so.0", RTLD_NOW);
734 _gnome_program_init_fn gnome_program_init = (_gnome_program_init_fn)
735 dlsym(mGnome,
"gnome_program_init");
736 _libgnomeui_module_info_get_fn libgnomeui_module_info_get = (_libgnomeui_module_info_get_fn)
737 dlsym(mGnomeui,
"libgnomeui_module_info_get");
738 _gnome_master_client_fn gnome_master_client = (_gnome_master_client_fn)
739 dlsym(mGnomeui,
"gnome_master_client");
741 gnome_client_request_interaction = (_gnome_client_request_interaction_fn)
742 dlsym(mGnomeui,
"gnome_client_request_interaction");
743 gnome_interaction_key_return = (_gnome_interaction_key_return_fn)
744 dlsym(mGnomeui,
"gnome_interaction_key_return");
747 if (!gnome_program_init || !libgnomeui_module_info_get) {
751 gnome_program_init(mArgv[0].get(),
753 libgnomeui_module_info_get(),
755 reinterpret_cast<char**
>(mArgv),
758 mClient = gnome_master_client();
759 if (mClient == NULL) {
763 g_signal_connect(mClient,
"save-yourself", G_CALLBACK(save_yourself_cb), NULL);
766 virtual ~GnomeShutdown()
776 GnomeClient *mClient;
781GnomeShutdown GnomeShutdownInstance;
794#define IPC_APPL wxT("audacity")
795#define IPC_TOPIC wxT("System")
809 bool OnExec(
const wxString & WXUNUSED(topic),
810 const wxString & data)
844#if defined(__WXMAC__)
849#include <ApplicationServices/ApplicationServices.h>
858 wxDISABLE_DEBUG_SUPPORT();
866 ProcessSerialNumber psn = { 0, kCurrentProcess };
867 TransformProcessType(&psn, kProcessTransformToUIElementApplication);
873#elif defined(__WXGTK__) && defined(NDEBUG)
885 wxDISABLE_DEBUG_SUPPORT();
892 freopen(
"/dev/null",
"w", stdout);
893 freopen(
"/dev/null",
"w", stderr);
898#elif defined(__WXGTK__)
902wxIMPLEMENT_WX_THEME_SUPPORT
908 wxDISABLE_DEBUG_SUPPORT();
916wxIMPLEMENT_WX_THEME_SUPPORT
917extern "C" int WINAPI WinMain(HINSTANCE hInstance,
918 HINSTANCE hPrevInstance,
919 wxCmdLineArgType lpCmdLine,
922 static CommandLineArgs::MSWParser wxArgs;
926 wxDISABLE_DEBUG_SUPPORT();
928 return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
961#ifdef HAS_CUSTOM_URL_HANDLING
962void AudacityApp::MacOpenURL (
const wxString& url)
965 ofqueue.push_back(urlPrefix + url);
972#define ID_IPC_SERVER 6200
973#define ID_IPC_SOCKET 6201
976#define kAudacityAppTimerID 0
1024 auto proj = pProj.get();
1026 if (!fullPathStr.empty())
1029 if (wxFile::Exists(fullPathStr))
1048"%s could not be found.\n\nIt has been removed from the list of recent files.")
1058 return GuardedCall< bool >( [&]{
return MRUOpen( fullPathStr ); } );
1072 const auto &fullPathStr = history[ n ];
1106 window.RequestUserAttention();
1111 #ifdef HAS_CUSTOM_URL_HANDLING
1112 if (
name.StartsWith(urlPrefix))
1114 const auto utf8Url =
name.ToUTF8();
1115 const size_t prefixSize = urlPrefix.Length();
1117 if (utf8Url.length() <= prefixSize)
1121 { utf8Url.data() + prefixSize,
1122 utf8Url.length() - prefixSize });
1137 wxLogMessage(
wxT(
"MRUOpen failed"));
1144#if defined(__WXMSW__)
1145#define WL(lang, sublang) (lang), (sublang),
1147#define WL(lang,sublang)
1150#if wxCHECK_VERSION(3, 0, 1) && !wxCHECK_VERSION(3, 1, 6)
1151wxLanguageInfo userLangs[] =
1154 { wxLANGUAGE_USER_DEFINED,
wxT(
"eu"),
WL(0, SUBLANG_DEFAULT)
wxT(
"Basque"), wxLayout_LeftToRight },
1160#if defined(HAS_CRASH_REPORT)
1161 CrashReport::Generate(wxDebugReport::Context_Exception);
1170#pragma warning( push )
1171#pragma warning( disable : 4702)
1188 auto pException = std::current_exception();
1203 try { std::rethrow_exception( pException ); }
1215 return wxApp::OnExceptionInMainLoop();
1221#pragma warning( pop )
1258 -> std::unique_ptr<BasicUI::WindowPlacement> {
1259 return std::make_unique<wxWidgetsWindowPlacement>(
1268 XO(
"SQLite library failed to initialize. Audacity cannot continue.") );
1276#if defined(__WXMAC__)
1278 wxSystemOptions::SetOption(wxMAC_WINDOW_PLAIN_TRANSITION, 1);
1284#if defined(__WXGTK3__) && defined(HAVE_GTK)
1285 GtkWidget *combo = gtk_combo_box_new();
1286 GtkCssProvider *provider = gtk_css_provider_new();
1287 gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
1290 ".linked combobox box.linked button,\n"
1291 ".horizontal.linked entry,\n"
1292 ".horizontal.linked button,\n"
1293 ".horizontal.linked combobox box.linked button,\n"
1295 " padding-top: 0px;\n"
1296 " padding-bottom: 0px;\n"
1297 " padding-left: 4px;\n"
1298 " padding-right: 4px;\n"
1300 " font-size: 95%;\n"
1302 gtk_style_context_add_provider_for_screen(gtk_widget_get_screen(combo),
1303 GTK_STYLE_PROVIDER (provider),
1304 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1305 g_object_unref(provider);
1306 g_object_unref(combo);
1307#elif defined(__WXGTK__) && defined(HAVE_GTK)
1308 gtk_rc_parse_string(
"style \"audacity\" {\n"
1309 " GtkButton::inner_border = { 0, 0, 0, 0 }\n"
1310 " GtkEntry::inner_border = { 0, 0, 0, 0 }\n"
1314 "widget_class \"*GtkCombo*\" style \"audacity\"");
1317 wxTheApp->SetAppName(
AppName);
1319 wxTheApp->SetAppDisplayName(
AppName);
1320 wxTheApp->SetVendorName(
AppName);
1322 ::wxInitAllImageHandlers();
1325 wxFileSystem::AddHandler(
safenew wxZipFSHandler);
1343 wxEventLoopGuarantor eventLoop;
1354#if wxCHECK_VERSION(3, 0, 1) && !wxCHECK_VERSION(3, 1, 6)
1355 for (
size_t i = 0, cnt = WXSIZEOF(userLangs); i < cnt; i++)
1357 wxLocale::AddLanguage(userLangs[i]);
1364 auto appName = wxTheApp->GetAppName();
1366 appName, wxEmptyString,
1367 configFileName.GetFullPath(),
1368 wxEmptyString, wxCONFIG_USE_LOCAL_FILE) );
1401 using namespace std::chrono;
1404 std::this_thread::sleep_for(100ms);
1417#if defined(__WXMAC__)
1418 SetExitOnFrameDelete(
false);
1424 PreferenceKey(FileNames::Operation::Temp, FileNames::PathType::_None);
1457 wxString journalFileName;
1458 const bool playingJournal = parser->Found(
"j", &journalFileName);
1460#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
1461 if (!playingJournal)
1465 if (parser->Found(
wxT(
"v")))
1467 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
1472 if (parser->Found(
wxT(
"b"), &lval))
1474 if (lval < 256 || lval > 100000000)
1476 wxPrintf(
_(
"Block size must be within 256 to 100000000\n"));
1487 wxImage logoimage((
const char **)AudacityLogoWithName_xpm);
1488 logoimage.Rescale(logoimage.GetWidth() / 2, logoimage.GetHeight() / 2);
1489 if( GetLayoutDirection() == wxLayout_RightToLeft)
1490 logoimage = logoimage.Mirror();
1491 wxBitmap logo(logoimage);
1498 bool bMaximized =
false;
1499 bool bIconized =
false;
1502 wxSplashScreen temporarywindow(
1504 wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT,
1508 wndRect.GetTopLeft(),
1520 temporarywindow.SetPosition( wndRect.GetTopLeft() );
1522 temporarywindow.Center();
1523 temporarywindow.SetTitle(
_(
"Audacity is starting up..."));
1524 SetTopWindow(&temporarywindow);
1525 temporarywindow.Raise();
1529 wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
1543 auto fileMenu = std::make_unique<wxMenu>();
1544 auto urecentMenu = std::make_unique<wxMenu>();
1545 auto recentMenu = urecentMenu.get();
1546 fileMenu->Append(wxID_NEW, wxString(
_(
"&New")) +
wxT(
"\tCtrl+N"));
1547 fileMenu->Append(wxID_OPEN, wxString(
_(
"&Open...")) +
wxT(
"\tCtrl+O"));
1548 fileMenu->AppendSubMenu(urecentMenu.release(),
_(
"Open &Recent..."));
1549 fileMenu->Append(wxID_ABOUT,
_(
"&About Audacity..."));
1550 fileMenu->Append(wxID_PREFERENCES, wxString(
_(
"&Preferences...")) +
wxT(
"\tCtrl+,"));
1553 auto menuBar = std::make_unique<wxMenuBar>();
1554 menuBar->Append(fileMenu.release(),
_(
"&File"));
1558 wxMenuBar::MacSetCommonMenuBar(menuBar.release());
1562 recentFiles.UseMenu(recentMenu);
1565 temporarywindow.Show(
false);
1569 std::vector<wxString> failedPlugins;
1573 if(!newPlugins.empty())
1577 failedPlugins =
reg.GetFailedPluginsPaths();
1607#if defined(HAVE_UPDATES_CHECK)
1620 int vMajorInit, vMinorInit, vMicroInit;
1622 if (vMajorInit != AUDACITY_VERSION || vMinorInit != AUDACITY_RELEASE
1623 || vMicroInit != AUDACITY_REVISION) {
1629 bool didRecoverAnything =
false;
1631 if (!playingJournal)
1642 if (project && !didRecoverAnything)
1644 if (parser->Found(
wxT(
"t")))
1650 for (
size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
1657 if(!failedPlugins.empty())
1660 dialog->Bind(wxEVT_CLOSE_WINDOW, [dialog](wxCloseEvent&) { dialog->Destroy(); });
1673#ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS
1676 if (::wxGetMouseState().ShiftDown()) {
1693#if defined(__WXMAC__)
1701 bool permsReset =
false;
1702 gPrefs->Read(
wxT(
"/MicrophonePermissionsReset"), &permsReset,
false);
1704 system(
"tccutil reset Microphone org.audacityteam.audacity");
1705 gPrefs->Write(
wxT(
"/MicrophonePermissionsReset"),
true);
1709#if defined(__WXMAC__)
1711 Bind(wxEVT_MENU_OPEN, [=](wxMenuEvent &event)
1713 wxSetlocale(LC_NUMERIC, wxString(
wxT(
"C")));
1717 Bind(wxEVT_MENU_CLOSE, [=](wxMenuEvent &event)
1724#ifdef HAS_CUSTOM_URL_HANDLING
1729 if (parser->Found(
"u", &url))
1731 auto utf8Url = url.ToUTF8();
1742 auto result = wxApp::OnRun();
1780 if(event.GetKeyCode() == WXK_ESCAPE) {
1785 auto scrubbing = scrubber.HasMark();
1790 gAudioIO->IsAudioTokenActive(token) &&
1791 gAudioIO->GetNumCaptureChannels() == 0) ||
1809 if( wxDirExists( dir ) ){
1814 wxFileName
name( dir +
"/junkname.cfg" );
1815 if(
name.Mkdir( wxS_DIR_DEFAULT , wxPATH_MKDIR_FULL ) )
1828 if (tempFromPrefs.length() > 0 && tempFromPrefs[0] !=
wxT(
'/'))
1829 tempFromPrefs =
wxT(
"");
1847 struct stat tempStatBuf;
1848 if ( lstat(temp.mb_str(), &tempStatBuf) != 0 ) {
1852 if ( geteuid() != tempStatBuf.st_uid ) {
1862"Audacity could not find a safe place to store temporary files.\nAudacity needs a place where automatic cleanup programs won't delete the temporary files.\nPlease enter an appropriate directory in the preferences dialog."));
1865"Audacity could not find a place to store temporary files.\nPlease enter an appropriate directory in the preferences dialog."));
1875"Audacity is now going to exit. Please launch Audacity again to use the new temporary directory."));
1891#if defined(__WXMSW__)
1898 wxString
name = wxString::Format(
wxT(
"audacity-lock-%s"), wxGetUserId());
1900 auto checker = std::make_unique<wxSingleInstanceChecker>();
1902 auto runningTwoCopiesStr =
XO(
"Running two copies of Audacity simultaneously may cause\ndata loss or cause your system to crash.\n\n");
1904 if (!checker->Create(
name, dir))
1910"Audacity was not able to lock the temporary files directory.\nThis folder may be in use by another copy of Audacity.\n")
1911 + runningTwoCopiesStr
1912 +
XO(
"Do you still want to start Audacity?");
1915 XO(
"Error Locking Temporary Folder"),
1916 wxYES_NO | wxICON_EXCLAMATION, NULL);
1920 else if ( checker->IsAnotherRunning() ) {
1930 if (parser->Found(
wxT(
"v")))
1932 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
1939 for (
size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
1941 wxFileName filename(parser->GetParam(i));
1942 if (filename.MakeAbsolute())
1944 filenames.push_back(filename.GetLongPath());
1948 #ifdef HAS_CUSTOM_URL_HANDLING
1950 parser->Found(
"u", &url);
1962 for (
int i = 0; i < 50; i++)
1964 std::unique_ptr<wxConnectionBase> conn{ client.MakeConnection(wxEmptyString,
IPC_APPL,
IPC_TOPIC) };
1968 #ifdef HAS_CUSTOM_URL_HANDLING
1971 if (!conn->Execute(urlPrefix + url))
1976 if (filenames.size() > 0)
1978 for (
size_t i = 0, cnt = filenames.size(); i < cnt; i++)
1980 ok = conn->Execute(filenames[i]);
1986 ok = conn->Execute(wxEmptyString);
1993 using namespace std::chrono;
1994 std::this_thread::sleep_for(10ms);
1999"The system has detected that another copy of Audacity is running.\n")
2000 + runningTwoCopiesStr
2002"Use the New or Open commands in the currently running Audacity\nprocess to open multiple projects simultaneously.\n");
2004 prompt,
XO(
"Audacity is already running"),
2005 wxOK | wxICON_ERROR);
2017#if defined(__UNIX__)
2030 bool isServer =
false;
2034 struct sembuf op = {};
2038 key_t memkey = ftok(datadir.c_str(), 0);
2039 key_t servkey = ftok(datadir.c_str(), 1);
2040 key_t lockkey = ftok(datadir.c_str(), 2);
2044 int memid = shmget(memkey,
sizeof(
int), IPC_CREAT | S_IRUSR | S_IWUSR);
2048 XO(
"Unable to create shared memory segment.\n\n"
2049 "error code=%d : \"%s\".").
Format(errno, strerror(errno)),
2050 XO(
"Audacity Startup Failure"),
2051 wxOK | wxICON_ERROR);
2056 int *portnum = (
int *) shmat(memid,
nullptr, 0);
2059 int servid = semget(servkey, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
2062 int lockid = semget(lockkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
2075 semctl(servid, 0, SETVAL, 1);
2076 semctl(lockid, 0, SETVAL, 1);
2082 op.sem_flg = SEM_UNDO;
2083 if (semop(lockid, &op, 1) == -1 || semop(servid, &op, 1) == -1)
2086 XO(
"Unable to acquire semaphores.\n\n"
2087 "This is likely due to a resource shortage\n"
2088 "and a reboot may be required."),
2089 XO(
"Audacity Startup Failure"),
2090 wxOK | wxICON_ERROR);
2099 else if (errno != EEXIST)
2102 XO(
"Unable to create semaphores.\n\n"
2103 "This is likely due to a resource shortage\n"
2104 "and a reboot may be required."),
2105 XO(
"Audacity Startup Failure"),
2106 wxOK | wxICON_ERROR);
2115 lockid = semget(lockkey, 1, 0);
2121 op.sem_flg = SEM_UNDO;
2122 if (semop(lockid, &op, 1) == -1)
2125 XO(
"Unable to acquire lock semaphore.\n\n"
2126 "This is likely due to a resource shortage\n"
2127 "and a reboot may be required."),
2128 XO(
"Audacity Startup Failure"),
2129 wxOK | wxICON_ERROR);
2139 op.sem_flg = IPC_NOWAIT | SEM_UNDO;
2140 if (semop(servid, &op, 1) == 0)
2144 else if (errno != EAGAIN)
2147 XO(
"Unable to acquire server semaphore.\n\n"
2148 "This is likely due to a resource shortage\n"
2149 "and a reboot may be required."),
2150 XO(
"Audacity Startup Failure"),
2151 wxOK | wxICON_ERROR);
2164 auto serv = std::make_unique<wxSocketServer>(addr, wxSOCKET_NOWAIT);
2165 if (serv && serv->IsOk())
2168 serv->SetNotify(wxSOCKET_CONNECTION_FLAG);
2175 *portnum = addr.Service();
2184 semop(lockid, &op, 1);
2190 XO(
"The Audacity IPC server failed to initialize.\n\n"
2191 "This is likely due to a resource shortage\n"
2192 "and a reboot may be required."),
2193 XO(
"Audacity Startup Failure"),
2194 wxOK | wxICON_ERROR);
2205 addr.Service(*portnum);
2210 semop(lockid, &op, 1);
2221 sock->SetFlags(wxSOCKET_WAITALL);
2224 sock->Connect(addr,
true);
2225 if (!sock->IsConnected())
2231 XO(
"An unrecoverable error has occurred during startup"),
2232 XO(
"Audacity Startup Failure"),
2233 wxOK | wxICON_ERROR);
2248 if (parser->Found(
wxT(
"v")))
2250 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
2255#ifdef HAS_CUSTOM_URL_HANDLING
2258 if (parser->Found(
wxT(
"u"), &url))
2262 url = urlPrefix + url;
2263 auto str = url.c_str().AsWChar();
2265 sock->WriteMsg(
str, (url.length() + 1) *
sizeof(*
str));
2270#if defined(__WXMAC__)
2274 for (
const auto &filename:
ofqueue)
2276 auto str = filename.c_str().AsWChar();
2277 sock->WriteMsg(
str, (filename.length() + 1) *
sizeof(*
str));
2283 for (
size_t j = 0, cnt = parser->GetParamCount(); j < cnt; ++j)
2285 wxFileName filename(parser->GetParam(j));
2286 if (filename.MakeAbsolute())
2288 const wxString param = filename.GetLongPath();
2289 sock->WriteMsg((
const wxChar *) param, (param.length() + 1) *
sizeof(wxChar));
2294 sock->WriteMsg(wxEmptyString,
sizeof(wxChar));
2313 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
2321 wxSocketBase *sock = evt.GetSocket();
2323 if (evt.GetSocketEvent() == wxSOCKET_LOST)
2330 wxChar
name[PATH_MAX];
2331 sock->ReadMsg(&
name,
sizeof(
name));
2344 auto parser = std::make_unique<wxCmdLineParser>(
argc,
argv);
2352 parser->AddOption(
wxT(
"b"),
wxT(
"blocksize"),
_(
"set max disk block size in bytes"),
2353 wxCMD_LINE_VAL_NUMBER);
2355 const auto journalOptionDescription =
2359 _(
"replay a journal file");
2361 parser->AddOption(
wxT(
"j"),
wxT(
"journal"), journalOptionDescription);
2364 parser->AddSwitch(
wxT(
"h"),
wxT(
"help"),
_(
"this help message"),
2365 wxCMD_LINE_OPTION_HELP);
2368 parser->AddSwitch(
wxT(
"t"),
wxT(
"test"),
_(
"run self diagnostics"));
2371 parser->AddSwitch(
wxT(
"v"),
wxT(
"version"),
_(
"display Audacity version"));
2375 parser->AddParam(
_(
"audio or project file name"),
2376 wxCMD_LINE_VAL_STRING,
2377 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL);
2379#ifdef HAS_CUSTOM_URL_HANDLING
2381 parser->AddOption(
wxT(
"u"),
wxT(
"url"),
_(
"Handle 'audacity://' url"));
2385 if (parser->Parse() == 0)
2393 bool mustVeto =
false;
2396 mustVeto = wxDialog::OSXHasModalDialogsOpen();
2407 bool force = !
event.CanVeto();
2436 bool bFalse =
false;
2438 if(
gPrefs->Read(
wxT(
"/QDeleteCmdCfgLocation"), &bFalse))
2441 gPrefs->Write(
wxT(
"/DeleteCmdCfgLocation"),
true);
2452#ifdef HAS_NETWORKING
2576#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
2580 bool bWantAssociateFiles =
true;
2581 if (
gPrefs->Read(
wxT(
"/WantAssociateFiles"), &bWantAssociateFiles) &&
2582 !bWantAssociateFiles)
2588 wxRegKey associateFileTypes;
2590 auto IsDefined = [&](
const wxString &type)
2592 associateFileTypes.SetName(wxString::Format(
wxT(
"HKCR\\%s"), type));
2593 bool bKeyExists = associateFileTypes.Exists();
2597 associateFileTypes.SetName(wxString::Format(
wxT(
"HKCU\\Software\\Classes\\%s"), type));
2598 bKeyExists = associateFileTypes.Exists();
2603 auto DefineType = [&](
const wxString &type)
2605 wxString root_key =
wxT(
"HKCU\\Software\\Classes\\");
2608 associateFileTypes.SetName(wxString::Format(
wxT(
"%s%s"), root_key, type));
2609 if (!associateFileTypes.Create(
true))
2612 root_key =
wxT(
"HKCR\\");
2613 associateFileTypes.SetName(wxString::Format(
wxT(
"%s%s"), root_key, type));
2614 if (!associateFileTypes.Create(
true))
2621 if (!root_key.empty())
2623 associateFileTypes =
wxT(
"Audacity.Project");
2630 if (IsDefined(
wxT(
".aup3")) && IsDefined(
wxT(
".aup")) && IsDefined(
wxT(
"Audacity.Project")))
2640"Audacity project (.aup3) files are not currently \nassociated with Audacity. \n\nAssociate them, so they open on double-click?"),
2641 XO(
"Audacity Project Files"),
2642 wxYES_NO | wxICON_QUESTION);
2644 if (wantAssoc == wxNO)
2647 gPrefs->Write(
wxT(
"/WantAssociateFiles"),
false);
2653 gPrefs->Write(
wxT(
"/WantAssociateFiles"),
true);
2658 root_key = DefineType(
wxT(
".aup3"));
2659 if (root_key.empty())
2665 DefineType(
wxT(
".aup"));
2667 associateFileTypes =
wxT(
"Audacity.Project");
2668 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project"));
2669 if (!associateFileTypes.Exists())
2671 associateFileTypes.Create(
true);
2672 associateFileTypes =
wxT(
"Audacity Project File");
2675 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell"));
2676 if (!associateFileTypes.Exists())
2678 associateFileTypes.Create(
true);
2679 associateFileTypes =
wxT(
"");
2682 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open"));
2683 if (!associateFileTypes.Exists())
2685 associateFileTypes.Create(
true);
2688 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\command"));
2689 wxString tmpRegAudPath;
2690 if(associateFileTypes.Exists())
2692 tmpRegAudPath = associateFileTypes.QueryDefaultValue().Lower();
2695 if (!associateFileTypes.Exists() ||
2696 (tmpRegAudPath.Find(
wxT(
"audacity.exe")) >= 0))
2698 associateFileTypes.Create(
true);
2699 associateFileTypes = (wxString)
argv[0] + (wxString)
wxT(
" \"%1\"");
2706 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec"));
2707 if (!associateFileTypes.Exists())
2709 associateFileTypes.Create(
true);
2710 associateFileTypes =
wxT(
"%1");
2713 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec\\Application"));
2714 if (!associateFileTypes.Exists())
2716 associateFileTypes.Create(
true);
2720 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec\\Topic"));
2721 if (!associateFileTypes.Exists())
2723 associateFileTypes.Create(
true);
AUDACITY_DLL_API std::weak_ptr< AudacityProject > GetActiveProject()
Handle changing of active project and keep global project pointer.
EVT_MENU(OnSetPlayRegionToSelectionID, AdornedRulerPanel::OnSetPlayRegionToSelection) EVT_COMMAND(OnTogglePinnedStateID
Headers and event table macros for AppCommandEvent.
#define EVT_APP_COMMAND(winid, fn)
void SetToExtantDirectory(wxString &result, const wxString &dir)
int main(int argc, char *argv[])
#define WL(lang, sublang)
EVT_MENU_RANGE(FileHistory::ID_RECENT_FIRST, FileHistory::ID_RECENT_LAST, AudacityApp::OnMRUFile) bool AudacityApp
#define kAudacityAppTimerID
static void QuitAudacity(bool bForce)
static bool CloseAllProjects(bool force)
static wxArrayString ofqueue
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
static AudioUnitEffectsModule::Factory::SubstituteInUnique< AudioUnitEffect > scope
bool ShowAutoRecoveryDialogIfNeeded(AudacityProject *&pproj, bool *didRecoverAnything)
void RunBenchmark(wxWindow *parent, AudacityProject &project)
Contains declarations for the CommandHandler class.
static const AudacityProject::AttachedObjects::RegisteredFactory key
PrefsPanel::Factory DirectoriesPrefsFactory()
const TranslatableString name
PrefsPanel::Factory KeyConfigPrefsFactory(const CommandID &name)
std::unique_ptr< Character[], freer > MallocString
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
const std::wstring AppName
This program's name.
Declare a class for performing HTTP requests.
void InitPreferences(std::unique_ptr< FileConfig > uPrefs)
void ResetPreferences()
Call this to reset preferences to an (almost)-"new" default state.
#define AUDACITY_PREFS_VERSION_STRING
void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
wxFrame * FindProjectFrame(AudacityProject *project)
Get a pointer to the window associated with a project, or null if the given pointer is null,...
AUDACITY_DLL_API wxFrame & GetProjectFrame(AudacityProject &project)
Get the top-level window associated with the project (as a wxFrame only, when you do not need to use ...
accessors for certain important windows associated with each project
declares abstract base class Track, TrackList, and iterators over TrackList
Declare a class that handles managing of updates.
The AboutDialog shows the program version and developer credits.
static AboutDialog * ActiveIntance()
const_iterator begin() const
An event 'envelope' for sending Command objects through the wxwidgets event loop.
AudacityApp is the 'main' class for Audacity.
void OnQueryEndSession(wxCloseEvent &event)
void OnMenuExit(wxCommandEvent &event)
void MacPrintFile(const wxString &fileName) override
bool OSXIsGUIApplication() override
bool MRUOpen(const FilePath &fileName)
void OnKeyDown(wxKeyEvent &event)
void OnMenuPreferences(wxCommandEvent &event)
bool OnExceptionInMainLoop() override
void OnServerEvent(wxSocketEvent &evt)
void OnEndSession(wxCloseEvent &event)
void MacNewFile() override
void OnTimer(wxTimerEvent &event)
bool Initialize(int &argc, wxChar **argv) override
std::unique_ptr< CommandHandler > mCmdHandler
std::unique_ptr< wxSingleInstanceChecker > mChecker
void MacFinishLaunching()
Observer::Subscription mThemeChangeSubscription
void OnMRUFile(wxCommandEvent &event)
void AssociateFileTypes()
void OnMenuOpen(wxCommandEvent &event)
std::unique_ptr< wxCmdLineParser > ParseCommandLine()
void OnFatalException() override
void OnIdle(wxIdleEvent &)
void OnMRUClear(wxCommandEvent &event)
int OnExit(void) override
void OnMenuAbout(wxCommandEvent &event)
bool CreateSingleInstanceChecker(const wxString &dir)
void InitCommandHandler()
void MacOpenFile(const wxString &fileName) override
void OnMenuNew(wxCommandEvent &event)
static void OnThemeChange(struct ThemeChangeMessage)
bool SafeMRUOpen(const wxString &fileName)
void OnReceiveCommand(AppCommandEvent &event)
std::unique_ptr< IPCServ > mIPCServ
void OnSocketEvent(wxSocketEvent &evt)
Base class for exceptions specially processed by the application.
virtual void DelayedHandlerAction()=0
Action to do in the main thread at idle time of the event loop.
static std::unique_ptr< AudacityFileConfig > Create(const wxString &appName={}, const wxString &vendorName={}, const wxString &localFilename={}, const wxString &globalFilename={}, long style=wxCONFIG_USE_LOCAL_FILE|wxCONFIG_USE_GLOBAL_FILE, const wxMBConv &conv=wxConvAuto())
Require a call to this factory, to guarantee proper two-phase initialization.
static AudacityLogger * Get()
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
static CommandManager & Get(AudacityProject &project)
void RemoveDuplicateShortcuts()
virtual bool DeleteEntry(const wxString &key, bool bDeleteGroupIfEmpty=true) wxOVERRIDE
void GetVersionKeysInit(int &major, int &minor, int µ) const
void SetVersionKeysInit(int major, int minor, int micro)
virtual bool GetNextGroup(wxString &str, long &lIndex) const wxOVERRIDE
virtual bool DeleteGroup(const wxString &key) wxOVERRIDE
virtual bool GetFirstGroup(wxString &str, long &lIndex) const wxOVERRIDE
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
virtual const wxString & GetPath() const wxOVERRIDE
virtual void SetPath(const wxString &strPath) wxOVERRIDE
Similar to wxFileHistory, but customized to our needs.
void Save(wxConfigBase &config)
static FileHistory & Global()
static void Destroy()
Destroys the dialog to prevent Audacity from hanging on exit.
typename GlobalVariable< Tag, const std::function< Signature >, Default, Options... >::Scope Scope
bool OnExec(const wxString &WXUNUSED(topic), const wxString &data)
wxConnectionBase * OnAcceptConnection(const wxString &topic) override
IPCServ(const wxString &appl)
static void Destroy()
Destroys the log window (if any)
static ModuleManager & Get()
int Dispatch(ModuleDispatchTypes type)
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
static bool IsHostProcess()
Returns true if current process is considered to be a plugin host process.
std::map< wxString, std::vector< wxString > > CheckPluginUpdates()
Ensures that all currently registered plugins still exist and scans for new ones.
void Initialize(FileConfigFactory factory)
static PluginManager & Get()
std::vector< PrefsPanel::PrefsNode > Factories
int GetAudioIOToken() const
static ProjectAudioIO & Get(AudacityProject &project)
void Stop(bool stopStream=true)
static ProjectAudioManager & Get(AudacityProject &project)
static bool InitializeSQL()
static bool IsAlreadyOpen(const FilePath &projPathName)
static ProjectHistory & Get(AudacityProject &project)
static AudacityProject * New()
static void SaveWindowSize()
static void OpenFiles(AudacityProject *proj)
static AudacityProject * OpenProject(AudacityProject *pGivenProject, const FilePath &fileNameArg, bool addtohistory, bool reuseNonemptyProject)
Open a file into an AudacityProject, returning the project, or nullptr for failure.
static void SetClosingAll(bool closing)
static ProjectSettings & Get(AudacityProject &project)
bool GetShowSplashScreen() const
static ProjectWindow & Get(AudacityProject &project)
void RedrawProject(const bool bForceWaveTracks=false)
static Scrubber & Get(AudacityProject &project)
static void SetMaxDiskBlockSize(size_t bytes)
static void DoHelpWelcome(AudacityProject &project)
static bool LoadPreferredTheme()
static TrackList & Get(AudacityProject &project)
void ClearPendingTracks(ListOfTracks *pAdded=nullptr)
bool RegisterScheme(std::string_view scheme)
Associates a new scheme with Audacity.
static URLSchemesRegistry & Get()
Retrieves the registry instance.
void HandleURL(std::string_view url)
static void Start(bool suppressModal)
static NetworkManager & GetInstance()
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
Services * Install(Services *pInstance)
Install an implementation; return the previously installed instance.
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
UTILITY_API const char *const * argv
A copy of argv; responsibility of application startup to assign it.
UTILITY_API int argc
A copy of argc; responsibility of application startup to assign it.
FILES_API FilePath Configuration()
FILES_API FilePath ResourcesDir()
FILES_API wxString PreferenceKey(FileNames::Operation op, FileNames::PathType type)
FILES_API FilePath StateDir()
Audacity user state directory.
FILES_API void InitializePathList()
FILES_API FilePath DataDir()
Audacity user data directory.
FILES_API void UpdateDefaultPath(Operation op, const FilePath &path)
FILES_API const FilePaths & AudacityPathList()
A list of directories that should be searched for Audacity files (plug-ins, help files,...
AUDACITY_DLL_API wxString SetLang(const wxString &lang)
bool sOSXIsGUIApplication
bool Begin(const FilePath &dataDir)
void SetInputFileName(const wxString &path)
wxString GetSystemLanguageCode(const FilePaths &pathList)
FILES_API bool IsTempDirectoryNameOK(const FilePath &Name)
FILES_API wxString TempDir()
FILES_API void ResetTempDir()
FILES_API const FilePath & DefaultTempDir()
THEME_RESOURCES_API void Load()
void PopulatePreferences()
BuiltinCommandsModule::Registration< CompareAudioCommand > reg
std::string ToUTF8(const std::wstring &wstr)