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>
120#if defined(HAVE_UPDATES_CHECK)
128#ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS
140#if defined(USE_BREAKPAD)
142#elif defined(USE_CRASHPAD)
146#ifdef EXPERIMENTAL_SCOREALIGN
154 static char*THIS_FILE= __FILE__;
155 #define new new(_NORMAL_BLOCK, THIS_FILE, __LINE__)
161#ifdef EXPERIMENTAL_DA
162#include "../images/DarkAudacityLogoWithName.xpm"
164#include "../images/AudacityLogoWithName.xpm"
172#ifdef HAS_CUSTOM_URL_HANDLING
177static wxString urlPrefix =
wxT(
"url:");
187static void wxOnAssert(
const wxChar *fileName,
int lineNumber,
const wxChar *msg)
190 wxPrintf(
"ASSERTION FAILED: %s\n%s: %d\n", (
const char *)wxString(msg).mb_str(), (
const char *)wxString(fileName).mb_str(), lineNumber);
192 wxPrintf(
"ASSERTION FAILED!\n%s: %d\n", (
const char *)wxString(fileName).mb_str(), lineNumber);
208 bool resetPrefs =
false;
209 wxString langCode =
gPrefs->
Read(
wxT(
"/Locale/Language"), wxEmptyString);
210 bool writeLang =
false;
214 wxT(
"FirstTime.ini"));
217 const wxString fullPath{
fn.GetFullPath()};
221 wxCONFIG_USE_LOCAL_FILE);
225 if (ini.Read(
wxT(
"/FromInno/Language"), &lang) && !lang.empty())
233 langCode.Replace(
wxT(
"0"),
wxT(
"@"));
236 ini.Read(
wxT(
"/FromInno/ResetPrefs"), &resetPrefs,
false);
238 bool gone = wxRemoveFile(fullPath);
242 XO(
"Failed to remove %s").
Format(fullPath),
248 if (langCode.empty())
259"Reset Preferences?\n\nThis is a one-time question, after an 'install' where you asked to have the Preferences reset.");
262 XO(
"Reset Audacity Preferences"),
281 bool newPrefsInitialized =
false;
282 gPrefs->
Read(
wxT(
"/NewPrefsInitialized"), &newPrefsInitialized,
false);
283 if (newPrefsInitialized) {
307 (vMajor == 1 && vMinor < 3) ||
308 (vMajor == 1 && vMinor == 3 && vMicro < 13)) {
331 long dock, order, show, x, y, w, h;
347 const auto orderKey = group +
wxT(
"/Order");
348 if(
gPrefs->
Read(orderKey, &orderValue) && orderValue >= order)
376 if ((0<vMajor && vMajor < 2) ||
377 (vMajor == 2 && vMinor < 2))
383 if ((0<vMajor && vMajor < 2) ||
384 (vMajor == 2 && vMinor < 4))
398 if (std::pair{ vMajor, vMinor } < std::pair{ 3, 1 } ) {
403 if(std::pair{vMajor, vMinor} < std::pair{3, 2})
415 if(std::tuple{ vMajor, vMinor, vMicro } < std::tuple{ 3, 2, 3 })
423 if (std::pair { vMajor, vMinor } < std::pair { 3, 3 })
439#if defined(USE_BREAKPAD) || defined(USE_CRASHPAD)
440 wxFileName databasePath;
442 databasePath.AppendDir(
"crashreports");
443 databasePath.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
445 if(databasePath.DirExists())
447 const auto sentryRelease = wxString::Format(
448 "audacity@%d.%d.%d", AUDACITY_VERSION, AUDACITY_RELEASE, AUDACITY_REVISION);
449#if defined(USE_BREAKPAD)
453 #if defined(CRASH_REPORT_URL)
457 {
"version", wxString(AUDACITY_VERSION_STRING).ToUTF8().data() },
458 {
"sentry[release]", sentryRelease.ToUTF8().data() }
461#elif defined(USE_CRASHPAD)
465 const wxFileName crashpadHandlerPath(executableDir, CRASHPAD_HANDLER_NAME);
466 const wxFileName crashreporterPath(executableDir, CRASHREPORTER_NAME);
467 const wxFileName metricsDir = databasePath;
468 std::vector<std::string> arguments = {
469 wxString::Format(
"--crashreporter-path=%s", crashreporterPath.GetFullPath()).ToUTF8().data(),
470#if defined(CRASH_REPORT_URL)
472 "--crashreporter-argument=-u=%s",
473 CRASH_REPORT_URL).ToUTF8().data(),
475 "--crashreporter-argument=-a=version=\"%s\",sentry[release]=\"%s\"",
476 AUDACITY_VERSION_STRING,
477 sentryRelease).ToUTF8().data()
487 catch (std::exception& e)
489 wxLogError(
"Crashpad init error: %s", e.what());
493#elif !defined(_DEBUG)
494#if defined(HAS_CRASH_REPORT)
495#if defined(wxUSE_ON_FATAL_EXCEPTION) && wxUSE_ON_FATAL_EXCEPTION
496 wxHandleFatalExceptions();
536 wxTheApp->SetExitOnFrameDelete(
true);
568#ifdef EXPERIMENTAL_SCOREALIGN
569 CloseScoreAlignDialog();
575 #if !defined(__WXMAC__)
589 logger->SaveLog(logFile.GetFullPath());
593 std::unique_ptr<wxLog>{ wxLog::SetActiveTarget(NULL) };
606#if defined(__WXGTK__) && defined(HAVE_GTK)
626#include <glib-object.h>
628typedef struct _GnomeProgram GnomeProgram;
629typedef struct _GnomeModuleInfo GnomeModuleInfo;
630typedef struct _GnomeClient GnomeClient;
642 GNOME_INTERACT_ERRORS,
652typedef GnomeProgram * (*_gnome_program_init_fn)(
const char *,
654 const GnomeModuleInfo *,
659typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
660typedef GnomeClient * (*_gnome_master_client_fn)(void);
661typedef void (*GnomeInteractFunction)(GnomeClient *,
665typedef void (*_gnome_client_request_interaction_fn)(GnomeClient *,
667 GnomeInteractFunction,
669typedef void (*_gnome_interaction_key_return_fn)(gint, gboolean);
671static _gnome_client_request_interaction_fn gnome_client_request_interaction;
672static _gnome_interaction_key_return_fn gnome_interaction_key_return;
674static void interact_cb(GnomeClient * ,
679 wxCloseEvent e(wxEVT_QUERY_END_SESSION, wxID_ANY);
685 gnome_interaction_key_return(
key, e.GetVeto());
688static gboolean save_yourself_cb(GnomeClient *client,
692 GnomeInteractStyle interact,
696 if (!shutdown || interact != GNOME_INTERACT_ANY) {
704 gnome_client_request_interaction(client,
717 mArgv[0].reset(strdup(
"Audacity"));
719 mGnomeui = dlopen(
"libgnomeui-2.so.0", RTLD_NOW);
724 mGnome = dlopen(
"libgnome-2.so.0", RTLD_NOW);
729 _gnome_program_init_fn gnome_program_init = (_gnome_program_init_fn)
730 dlsym(mGnome,
"gnome_program_init");
731 _libgnomeui_module_info_get_fn libgnomeui_module_info_get = (_libgnomeui_module_info_get_fn)
732 dlsym(mGnomeui,
"libgnomeui_module_info_get");
733 _gnome_master_client_fn gnome_master_client = (_gnome_master_client_fn)
734 dlsym(mGnomeui,
"gnome_master_client");
736 gnome_client_request_interaction = (_gnome_client_request_interaction_fn)
737 dlsym(mGnomeui,
"gnome_client_request_interaction");
738 gnome_interaction_key_return = (_gnome_interaction_key_return_fn)
739 dlsym(mGnomeui,
"gnome_interaction_key_return");
742 if (!gnome_program_init || !libgnomeui_module_info_get) {
746 gnome_program_init(mArgv[0].get(),
748 libgnomeui_module_info_get(),
750 reinterpret_cast<char**
>(mArgv),
753 mClient = gnome_master_client();
754 if (mClient == NULL) {
758 g_signal_connect(mClient,
"save-yourself", G_CALLBACK(save_yourself_cb), NULL);
761 virtual ~GnomeShutdown()
771 GnomeClient *mClient;
776GnomeShutdown GnomeShutdownInstance;
789#define IPC_APPL wxT("audacity")
790#define IPC_TOPIC wxT("System")
804 bool OnExec(
const wxString & WXUNUSED(topic),
805 const wxString & data)
839#if defined(__WXMAC__)
844#include <ApplicationServices/ApplicationServices.h>
853 wxDISABLE_DEBUG_SUPPORT();
861 ProcessSerialNumber psn = { 0, kCurrentProcess };
862 TransformProcessType(&psn, kProcessTransformToUIElementApplication);
868#elif defined(__WXGTK__) && defined(NDEBUG)
880 wxDISABLE_DEBUG_SUPPORT();
887 freopen(
"/dev/null",
"w", stdout);
888 freopen(
"/dev/null",
"w", stderr);
893#elif defined(__WXGTK__)
897wxIMPLEMENT_WX_THEME_SUPPORT
903 wxDISABLE_DEBUG_SUPPORT();
911wxIMPLEMENT_WX_THEME_SUPPORT
912extern "C" int WINAPI WinMain(HINSTANCE hInstance,
913 HINSTANCE hPrevInstance,
914 wxCmdLineArgType lpCmdLine,
917 static CommandLineArgs::MSWParser wxArgs;
921 wxDISABLE_DEBUG_SUPPORT();
923 return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
956#ifdef HAS_CUSTOM_URL_HANDLING
957void AudacityApp::MacOpenURL (
const wxString& url)
960 ofqueue.push_back(urlPrefix + url);
967#define ID_IPC_SERVER 6200
968#define ID_IPC_SOCKET 6201
971#define kAudacityAppTimerID 0
1019 auto proj = pProj.get();
1021 if (!fullPathStr.empty())
1024 if (wxFile::Exists(fullPathStr))
1043"%s could not be found.\n\nIt has been removed from the list of recent files.")
1053 return GuardedCall< bool >( [&]{
return MRUOpen( fullPathStr ); } );
1067 const auto &fullPathStr = history[ n ];
1101 window.RequestUserAttention();
1106 #ifdef HAS_CUSTOM_URL_HANDLING
1107 if (
name.StartsWith(urlPrefix))
1109 const auto utf8Url =
name.ToUTF8();
1110 const size_t prefixSize = urlPrefix.Length();
1112 if (utf8Url.length() <= prefixSize)
1116 { utf8Url.data() + prefixSize,
1117 utf8Url.length() - prefixSize });
1132 wxLogMessage(
wxT(
"MRUOpen failed"));
1139#if defined(__WXMSW__)
1140#define WL(lang, sublang) (lang), (sublang),
1142#define WL(lang,sublang)
1145#if wxCHECK_VERSION(3, 0, 1) && !wxCHECK_VERSION(3, 1, 6)
1146wxLanguageInfo userLangs[] =
1149 { wxLANGUAGE_USER_DEFINED,
wxT(
"eu"),
WL(0, SUBLANG_DEFAULT)
wxT(
"Basque"), wxLayout_LeftToRight },
1155#if defined(HAS_CRASH_REPORT)
1156 CrashReport::Generate(wxDebugReport::Context_Exception);
1165#pragma warning( push )
1166#pragma warning( disable : 4702)
1183 auto pException = std::current_exception();
1198 try { std::rethrow_exception( pException ); }
1210 return wxApp::OnExceptionInMainLoop();
1216#pragma warning( pop )
1253 -> std::unique_ptr<BasicUI::WindowPlacement> {
1254 return std::make_unique<wxWidgetsWindowPlacement>(
1263 XO(
"SQLite library failed to initialize. Audacity cannot continue.") );
1271#if defined(__WXMAC__)
1273 wxSystemOptions::SetOption(wxMAC_WINDOW_PLAIN_TRANSITION, 1);
1279#if defined(__WXGTK3__) && defined(HAVE_GTK)
1280 GtkWidget *combo = gtk_combo_box_new();
1281 GtkCssProvider *provider = gtk_css_provider_new();
1282 gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
1285 ".linked combobox box.linked button,\n"
1286 ".horizontal.linked entry,\n"
1287 ".horizontal.linked button,\n"
1288 ".horizontal.linked combobox box.linked button,\n"
1290 " padding-top: 0px;\n"
1291 " padding-bottom: 0px;\n"
1292 " padding-left: 4px;\n"
1293 " padding-right: 4px;\n"
1295 " font-size: 95%;\n"
1297 gtk_style_context_add_provider_for_screen(gtk_widget_get_screen(combo),
1298 GTK_STYLE_PROVIDER (provider),
1299 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1300 g_object_unref(provider);
1301 g_object_unref(combo);
1302#elif defined(__WXGTK__) && defined(HAVE_GTK)
1303 gtk_rc_parse_string(
"style \"audacity\" {\n"
1304 " GtkButton::inner_border = { 0, 0, 0, 0 }\n"
1305 " GtkEntry::inner_border = { 0, 0, 0, 0 }\n"
1309 "widget_class \"*GtkCombo*\" style \"audacity\"");
1312 wxTheApp->SetAppName(
AppName);
1314 wxTheApp->SetAppDisplayName(
AppName);
1315 wxTheApp->SetVendorName(
AppName);
1317 ::wxInitAllImageHandlers();
1320 wxFileSystem::AddHandler(
safenew wxZipFSHandler);
1338 wxEventLoopGuarantor eventLoop;
1349#if wxCHECK_VERSION(3, 0, 1) && !wxCHECK_VERSION(3, 1, 6)
1350 for (
size_t i = 0, cnt = WXSIZEOF(userLangs); i < cnt; i++)
1352 wxLocale::AddLanguage(userLangs[i]);
1391 using namespace std::chrono;
1394 std::this_thread::sleep_for(100ms);
1407#if defined(__WXMAC__)
1408 SetExitOnFrameDelete(
false);
1414 PreferenceKey(FileNames::Operation::Temp, FileNames::PathType::_None);
1435 return std::make_unique<SettingsWX>(
1450 wxString journalFileName;
1451 const bool playingJournal = parser->Found(
"j", &journalFileName);
1453#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
1454 if (!playingJournal)
1458 if (parser->Found(
wxT(
"v")))
1460 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
1465 if (parser->Found(
wxT(
"b"), &lval))
1467 if (lval < 256 || lval > 100000000)
1469 wxPrintf(
_(
"Block size must be within 256 to 100000000\n"));
1480 wxImage logoimage((
const char **)AudacityLogoWithName_xpm);
1481 logoimage.Rescale(logoimage.GetWidth() / 2, logoimage.GetHeight() / 2);
1482 if( GetLayoutDirection() == wxLayout_RightToLeft)
1483 logoimage = logoimage.Mirror();
1484 wxBitmap logo(logoimage);
1491 bool bMaximized =
false;
1492 bool bIconized =
false;
1495 wxSplashScreen temporarywindow(
1497 wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT,
1501 wndRect.GetTopLeft(),
1513 temporarywindow.SetPosition( wndRect.GetTopLeft() );
1515 temporarywindow.Center();
1516 temporarywindow.SetTitle(
_(
"Audacity is starting up..."));
1517 SetTopWindow(&temporarywindow);
1518 temporarywindow.Raise();
1522 wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
1536 auto fileMenu = std::make_unique<wxMenu>();
1537 auto urecentMenu = std::make_unique<wxMenu>();
1538 auto recentMenu = urecentMenu.get();
1539 fileMenu->Append(wxID_NEW, wxString(
_(
"&New")) +
wxT(
"\tCtrl+N"));
1540 fileMenu->Append(wxID_OPEN, wxString(
_(
"&Open...")) +
wxT(
"\tCtrl+O"));
1541 fileMenu->AppendSubMenu(urecentMenu.release(),
_(
"Open &Recent..."));
1542 fileMenu->Append(wxID_ABOUT,
_(
"&About Audacity..."));
1543 fileMenu->Append(wxID_PREFERENCES, wxString(
_(
"&Preferences...")) +
wxT(
"\tCtrl+,"));
1546 auto menuBar = std::make_unique<wxMenuBar>();
1547 menuBar->Append(fileMenu.release(),
_(
"&File"));
1551 wxMenuBar::MacSetCommonMenuBar(menuBar.release());
1555 recentFiles.UseMenu(recentMenu);
1558 temporarywindow.Show(
false);
1562 std::vector<wxString> failedPlugins;
1566 if(!newPlugins.empty())
1570 failedPlugins =
reg.GetFailedPluginsPaths();
1600#if defined(HAVE_UPDATES_CHECK)
1610 int vMajorInit, vMinorInit, vMicroInit;
1612 if (vMajorInit != AUDACITY_VERSION || vMinorInit != AUDACITY_RELEASE
1613 || vMicroInit != AUDACITY_REVISION) {
1619 bool didRecoverAnything =
false;
1621 if (!playingJournal)
1632 if (
project && !didRecoverAnything)
1634 if (parser->Found(
wxT(
"t")))
1640 for (
size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
1647 if(!failedPlugins.empty())
1650 dialog->Bind(wxEVT_CLOSE_WINDOW, [dialog](wxCloseEvent&) { dialog->Destroy(); });
1663#ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS
1666 if (::wxGetMouseState().ShiftDown()) {
1683#if defined(__WXMAC__)
1691 bool permsReset =
false;
1692 gPrefs->
Read(
wxT(
"/MicrophonePermissionsReset"), &permsReset,
false);
1694 system(
"tccutil reset Microphone org.audacityteam.audacity");
1699#if defined(__WXMAC__)
1701 Bind(wxEVT_MENU_OPEN, [=](wxMenuEvent &event)
1703 wxSetlocale(LC_NUMERIC, wxString(
wxT(
"C")));
1707 Bind(wxEVT_MENU_CLOSE, [=](wxMenuEvent &event)
1714#ifdef HAS_CUSTOM_URL_HANDLING
1719 if (parser->Found(
"u", &url))
1721 auto utf8Url = url.ToUTF8();
1732 auto result = wxApp::OnRun();
1770 if(event.GetKeyCode() == WXK_ESCAPE) {
1775 auto scrubbing = scrubber.HasMark();
1780 gAudioIO->IsAudioTokenActive(token) &&
1781 gAudioIO->GetNumCaptureChannels() == 0) ||
1799 if( wxDirExists( dir ) ){
1804 wxFileName
name( dir +
"/junkname.cfg" );
1805 if(
name.Mkdir( wxS_DIR_DEFAULT , wxPATH_MKDIR_FULL ) )
1818 if (tempFromPrefs.length() > 0 && tempFromPrefs[0] !=
wxT(
'/'))
1819 tempFromPrefs =
wxT(
"");
1837 struct stat tempStatBuf;
1838 if ( lstat(temp.mb_str(), &tempStatBuf) != 0 ) {
1842 if ( geteuid() != tempStatBuf.st_uid ) {
1852"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."));
1855"Audacity could not find a place to store temporary files.\nPlease enter an appropriate directory in the preferences dialog."));
1865"Audacity is now going to exit. Please launch Audacity again to use the new temporary directory."));
1881#if defined(__WXMSW__)
1888 wxString
name = wxString::Format(
wxT(
"audacity-lock-%s"), wxGetUserId());
1890 auto checker = std::make_unique<wxSingleInstanceChecker>();
1892 auto runningTwoCopiesStr =
XO(
"Running two copies of Audacity simultaneously may cause\ndata loss or cause your system to crash.\n\n");
1894 if (!checker->Create(
name, dir))
1900"Audacity was not able to lock the temporary files directory.\nThis folder may be in use by another copy of Audacity.\n")
1901 + runningTwoCopiesStr
1902 +
XO(
"Do you still want to start Audacity?");
1905 XO(
"Error Locking Temporary Folder"),
1906 wxYES_NO | wxICON_EXCLAMATION, NULL);
1910 else if ( checker->IsAnotherRunning() ) {
1920 if (parser->Found(
wxT(
"v")))
1922 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
1929 for (
size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
1931 wxFileName filename(parser->GetParam(i));
1932 if (filename.MakeAbsolute())
1934 filenames.push_back(filename.GetLongPath());
1938 #ifdef HAS_CUSTOM_URL_HANDLING
1940 parser->Found(
"u", &url);
1952 for (
int i = 0; i < 50; i++)
1954 std::unique_ptr<wxConnectionBase> conn{ client.MakeConnection(wxEmptyString,
IPC_APPL,
IPC_TOPIC) };
1958 #ifdef HAS_CUSTOM_URL_HANDLING
1961 if (!conn->Execute(urlPrefix + url))
1966 if (filenames.size() > 0)
1968 for (
size_t i = 0, cnt = filenames.size(); i < cnt; i++)
1970 ok = conn->Execute(filenames[i]);
1976 ok = conn->Execute(wxEmptyString);
1983 using namespace std::chrono;
1984 std::this_thread::sleep_for(10ms);
1989"The system has detected that another copy of Audacity is running.\n")
1990 + runningTwoCopiesStr
1992"Use the New or Open commands in the currently running Audacity\nprocess to open multiple projects simultaneously.\n");
1994 prompt,
XO(
"Audacity is already running"),
1995 wxOK | wxICON_ERROR);
2007#if defined(__UNIX__)
2020 bool isServer =
false;
2024 struct sembuf op = {};
2028 key_t memkey = ftok(datadir.c_str(), 0);
2029 key_t servkey = ftok(datadir.c_str(), 1);
2030 key_t lockkey = ftok(datadir.c_str(), 2);
2034 int memid = shmget(memkey,
sizeof(
int), IPC_CREAT | S_IRUSR | S_IWUSR);
2038 XO(
"Unable to create shared memory segment.\n\n"
2039 "error code=%d : \"%s\".").
Format(errno, strerror(errno)),
2040 XO(
"Audacity Startup Failure"),
2041 wxOK | wxICON_ERROR);
2046 int *portnum = (
int *) shmat(memid,
nullptr, 0);
2049 int servid = semget(servkey, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
2052 int lockid = semget(lockkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
2065 semctl(servid, 0, SETVAL, 1);
2066 semctl(lockid, 0, SETVAL, 1);
2072 op.sem_flg = SEM_UNDO;
2073 if (semop(lockid, &op, 1) == -1 || semop(servid, &op, 1) == -1)
2076 XO(
"Unable to acquire semaphores.\n\n"
2077 "This is likely due to a resource shortage\n"
2078 "and a reboot may be required."),
2079 XO(
"Audacity Startup Failure"),
2080 wxOK | wxICON_ERROR);
2089 else if (errno != EEXIST)
2092 XO(
"Unable to create semaphores.\n\n"
2093 "This is likely due to a resource shortage\n"
2094 "and a reboot may be required."),
2095 XO(
"Audacity Startup Failure"),
2096 wxOK | wxICON_ERROR);
2105 lockid = semget(lockkey, 1, 0);
2111 op.sem_flg = SEM_UNDO;
2112 if (semop(lockid, &op, 1) == -1)
2115 XO(
"Unable to acquire lock semaphore.\n\n"
2116 "This is likely due to a resource shortage\n"
2117 "and a reboot may be required."),
2118 XO(
"Audacity Startup Failure"),
2119 wxOK | wxICON_ERROR);
2129 op.sem_flg = IPC_NOWAIT | SEM_UNDO;
2130 if (semop(servid, &op, 1) == 0)
2134 else if (errno != EAGAIN)
2137 XO(
"Unable to acquire server semaphore.\n\n"
2138 "This is likely due to a resource shortage\n"
2139 "and a reboot may be required."),
2140 XO(
"Audacity Startup Failure"),
2141 wxOK | wxICON_ERROR);
2154 auto serv = std::make_unique<wxSocketServer>(addr, wxSOCKET_NOWAIT);
2155 if (serv && serv->IsOk())
2158 serv->SetNotify(wxSOCKET_CONNECTION_FLAG);
2165 *portnum = addr.Service();
2174 semop(lockid, &op, 1);
2180 XO(
"The Audacity IPC server failed to initialize.\n\n"
2181 "This is likely due to a resource shortage\n"
2182 "and a reboot may be required."),
2183 XO(
"Audacity Startup Failure"),
2184 wxOK | wxICON_ERROR);
2195 addr.Service(*portnum);
2200 semop(lockid, &op, 1);
2211 sock->SetFlags(wxSOCKET_WAITALL);
2214 sock->Connect(addr,
true);
2215 if (!sock->IsConnected())
2221 XO(
"An unrecoverable error has occurred during startup"),
2222 XO(
"Audacity Startup Failure"),
2223 wxOK | wxICON_ERROR);
2238 if (parser->Found(
wxT(
"v")))
2240 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
2245#ifdef HAS_CUSTOM_URL_HANDLING
2248 if (parser->Found(
wxT(
"u"), &url))
2252 url = urlPrefix + url;
2253 auto str = url.c_str().AsWChar();
2255 sock->WriteMsg(
str, (url.length() + 1) *
sizeof(*
str));
2260#if defined(__WXMAC__)
2264 for (
const auto &filename:
ofqueue)
2266 auto str = filename.c_str().AsWChar();
2267 sock->WriteMsg(
str, (filename.length() + 1) *
sizeof(*
str));
2273 for (
size_t j = 0, cnt = parser->GetParamCount(); j < cnt; ++j)
2275 wxFileName filename(parser->GetParam(j));
2276 if (filename.MakeAbsolute())
2278 const wxString param = filename.GetLongPath();
2279 sock->WriteMsg((
const wxChar *) param, (param.length() + 1) *
sizeof(wxChar));
2284 sock->WriteMsg(wxEmptyString,
sizeof(wxChar));
2303 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
2311 wxSocketBase *sock = evt.GetSocket();
2313 if (evt.GetSocketEvent() == wxSOCKET_LOST)
2320 wxChar
name[PATH_MAX];
2321 sock->ReadMsg(&
name,
sizeof(
name));
2334 auto parser = std::make_unique<wxCmdLineParser>(
argc,
argv);
2342 parser->AddOption(
wxT(
"b"),
wxT(
"blocksize"),
_(
"set max disk block size in bytes"),
2343 wxCMD_LINE_VAL_NUMBER);
2345 const auto journalOptionDescription =
2349 _(
"replay a journal file");
2351 parser->AddOption(
wxT(
"j"),
wxT(
"journal"), journalOptionDescription);
2354 parser->AddSwitch(
wxT(
"h"),
wxT(
"help"),
_(
"this help message"),
2355 wxCMD_LINE_OPTION_HELP);
2358 parser->AddSwitch(
wxT(
"t"),
wxT(
"test"),
_(
"run self diagnostics"));
2361 parser->AddSwitch(
wxT(
"v"),
wxT(
"version"),
_(
"display Audacity version"));
2365 parser->AddParam(
_(
"audio or project file name"),
2366 wxCMD_LINE_VAL_STRING,
2367 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL);
2369#ifdef HAS_CUSTOM_URL_HANDLING
2371 parser->AddOption(
wxT(
"u"),
wxT(
"url"),
_(
"Handle 'audacity://' url"));
2375 if (parser->Parse() == 0)
2383 bool mustVeto =
false;
2386 mustVeto = wxDialog::OSXHasModalDialogsOpen();
2397 bool force = !
event.CanVeto();
2426 bool bFalse =
false;
2442#ifdef HAS_NETWORKING
2564#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
2568 bool bWantAssociateFiles =
true;
2569 if (
gPrefs->
Read(
wxT(
"/WantAssociateFiles"), &bWantAssociateFiles) &&
2570 !bWantAssociateFiles)
2576 wxRegKey associateFileTypes;
2578 auto IsDefined = [&](
const wxString &type)
2580 associateFileTypes.SetName(wxString::Format(
wxT(
"HKCR\\%s"), type));
2581 bool bKeyExists = associateFileTypes.Exists();
2585 associateFileTypes.SetName(wxString::Format(
wxT(
"HKCU\\Software\\Classes\\%s"), type));
2586 bKeyExists = associateFileTypes.Exists();
2591 auto DefineType = [&](
const wxString &type)
2593 wxString root_key =
wxT(
"HKCU\\Software\\Classes\\");
2596 associateFileTypes.SetName(wxString::Format(
wxT(
"%s%s"), root_key, type));
2597 if (!associateFileTypes.Create(
true))
2600 root_key =
wxT(
"HKCR\\");
2601 associateFileTypes.SetName(wxString::Format(
wxT(
"%s%s"), root_key, type));
2602 if (!associateFileTypes.Create(
true))
2609 if (!root_key.empty())
2611 associateFileTypes =
wxT(
"Audacity.Project");
2618 if (IsDefined(
wxT(
".aup3")) && IsDefined(
wxT(
".aup")) && IsDefined(
wxT(
"Audacity.Project")))
2628"Audacity project (.aup3) files are not currently \nassociated with Audacity. \n\nAssociate them, so they open on double-click?"),
2629 XO(
"Audacity Project Files"),
2630 wxYES_NO | wxICON_QUESTION);
2632 if (wantAssoc == wxNO)
2646 root_key = DefineType(
wxT(
".aup3"));
2647 if (root_key.empty())
2653 DefineType(
wxT(
".aup"));
2655 associateFileTypes =
wxT(
"Audacity.Project");
2656 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project"));
2657 if (!associateFileTypes.Exists())
2659 associateFileTypes.Create(
true);
2660 associateFileTypes =
wxT(
"Audacity Project File");
2663 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell"));
2664 if (!associateFileTypes.Exists())
2666 associateFileTypes.Create(
true);
2667 associateFileTypes =
wxT(
"");
2670 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open"));
2671 if (!associateFileTypes.Exists())
2673 associateFileTypes.Create(
true);
2676 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\command"));
2677 wxString tmpRegAudPath;
2678 if(associateFileTypes.Exists())
2680 tmpRegAudPath = associateFileTypes.QueryDefaultValue().Lower();
2683 if (!associateFileTypes.Exists() ||
2684 (tmpRegAudPath.Find(
wxT(
"audacity.exe")) >= 0))
2686 associateFileTypes.Create(
true);
2687 associateFileTypes = (wxString)
argv[0] + (wxString)
wxT(
" \"%1\"");
2694 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec"));
2695 if (!associateFileTypes.Exists())
2697 associateFileTypes.Create(
true);
2698 associateFileTypes =
wxT(
"%1");
2701 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec\\Application"));
2702 if (!associateFileTypes.Exists())
2704 associateFileTypes.Create(
true);
2708 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec\\Topic"));
2709 if (!associateFileTypes.Exists())
2711 associateFileTypes.Create(
true);
2721 static std::once_flag configSetupFlag;
2722 static std::shared_ptr<wxConfigBase> config;
2723 std::call_once(configSetupFlag, [&]{
2726 wxTheApp->GetAppName(), wxEmptyString,
2727 configFileName.GetFullPath(),
2728 wxEmptyString, wxCONFIG_USE_LOCAL_FILE);
2729 wxConfigBase::Set(config.get());
2731 return std::make_unique<SettingsWX>(config);
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
static audacity::ApplicationSettings::Scope applicationSettingsScope
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 SetPreferencesVersion(int vMajor, int vMinor, int vMicro)
audacity::BasicSettings * gPrefs
void GetPreferencesVersion(int &vMajor, int &vMinor, int &vMicro)
void InitPreferences(std::unique_ptr< audacity::BasicSettings > 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()
static ExportPluginRegistry & Get()
Similar to wxFileHistory, but customized to our needs.
void Save(audacity::BasicSettings &config)
static FileHistory & Global()
static void Destroy()
Destroys the dialog to prevent Audacity from hanging on exit.
static result_type Call(Arguments &&...arguments)
Null check of the installed function is done for you.
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(ConfigFactory 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)
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)
virtual bool Flush() noexcept=0
virtual bool Exists(const wxString &key) const
Returns true if group or entry exists.
GroupScope BeginGroup(const wxString &prefix)
Appends a prefix to the current group or sets a new absolute path. Group that was set as current befo...
bool DeleteGroup(const wxString &key)
Deletes specified group if exists.
virtual bool Write(const wxString &key, bool value)=0
bool DeleteEntry(const wxString &key)
Deletes specified entry if exists.
virtual bool Read(const wxString &key, bool *value) const =0
virtual wxArrayString GetChildGroups() const =0
Returns all child groups within the current group.
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.
ExportResult Show(ExportTask exportTask)
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()
auto Dispatch(Head_t< Types > &object, const TupleLike &functions, Args &&... args) -> std::enable_if_t< TypeListCheck_v< Types >, R >
void PopulatePreferences()
BuiltinCommandsModule::Registration< CompareAudioCommand > reg
std::string ToUTF8(const std::wstring &wstr)