26#include <wx/wxcrtvararg.h>
28#include <wx/evtloop.h>
30#include <wx/docview.h>
34#include <wx/snglinst.h>
36#include <wx/stdpaths.h>
38#include <wx/fontmap.h>
44#include <wx/filename.h>
62#include <wx/msw/registry.h>
118#if defined(HAVE_UPDATES_CHECK)
126#ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS
138#if defined(USE_BREAKPAD)
140#elif defined(USE_CRASHPAD)
144#ifdef EXPERIMENTAL_SCOREALIGN
152 static char*THIS_FILE= __FILE__;
153 #define new new(_NORMAL_BLOCK, THIS_FILE, __LINE__)
159#include "../images/Audacity-splash.xpm"
167#ifdef HAS_CUSTOM_URL_HANDLING
172static wxString urlPrefix =
wxT(
"url:");
182static void wxOnAssert(
const wxChar *fileName,
int lineNumber,
const wxChar *msg)
185 wxPrintf(
"ASSERTION FAILED: %s\n%s: %d\n", (
const char *)wxString(msg).mb_str(), (
const char *)wxString(fileName).mb_str(), lineNumber);
187 wxPrintf(
"ASSERTION FAILED!\n%s: %d\n", (
const char *)wxString(fileName).mb_str(), lineNumber);
203 bool resetPrefs =
false;
204 wxString langCode =
gPrefs->
Read(
wxT(
"/Locale/Language"), wxEmptyString);
205 bool writeLang =
false;
209 wxT(
"FirstTime.ini"));
212 const wxString fullPath{
fn.GetFullPath()};
216 wxCONFIG_USE_LOCAL_FILE);
220 if (ini.Read(
wxT(
"/FromInno/Language"), &lang) && !lang.empty())
228 langCode.Replace(
wxT(
"0"),
wxT(
"@"));
231 ini.Read(
wxT(
"/FromInno/ResetPrefs"), &resetPrefs,
false);
233 bool gone = wxRemoveFile(fullPath);
237 XO(
"Failed to remove %s").
Format(fullPath),
243 if (langCode.empty())
266 bool newPrefsInitialized =
false;
267 gPrefs->
Read(
wxT(
"/NewPrefsInitialized"), &newPrefsInitialized,
false);
268 if (newPrefsInitialized) {
292 (vMajor == 1 && vMinor < 3) ||
293 (vMajor == 1 && vMinor == 3 && vMicro < 13)) {
316 long dock, order, show, x, y, w, h;
332 const auto orderKey = group +
wxT(
"/Order");
333 if(
gPrefs->
Read(orderKey, &orderValue) && orderValue >= order)
361 if ((0<vMajor && vMajor < 2) ||
362 (vMajor == 2 && vMinor < 2))
368 if ((0<vMajor && vMajor < 2) ||
369 (vMajor == 2 && vMinor < 4))
383 if (std::pair{ vMajor, vMinor } < std::pair{ 3, 1 } ) {
388 if(std::pair{vMajor, vMinor} < std::pair{3, 2})
400 if(std::tuple{ vMajor, vMinor, vMicro } < std::tuple{ 3, 2, 3 })
408 if (std::pair { vMajor, vMinor } < std::pair { 3, 4 })
416 if (std::pair { vMajor, vMinor } < std::pair { 3, 5 })
432#if defined(USE_BREAKPAD) || defined(USE_CRASHPAD)
433 wxFileName databasePath;
435 databasePath.AppendDir(
"crashreports");
436 databasePath.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
438 if(databasePath.DirExists())
440 const auto sentryRelease = wxString::Format(
441 "audacity@%d.%d.%d", AUDACITY_VERSION, AUDACITY_RELEASE, AUDACITY_REVISION);
442#if defined(USE_BREAKPAD)
446 #if defined(CRASH_REPORT_URL)
450 {
"version", wxString(AUDACITY_VERSION_STRING).ToUTF8().data() },
451 {
"sentry[release]", sentryRelease.ToUTF8().data() }
454#elif defined(USE_CRASHPAD)
458 const wxFileName crashpadHandlerPath(executableDir, CRASHPAD_HANDLER_NAME);
459 const wxFileName crashreporterPath(executableDir, CRASHREPORTER_NAME);
460 const wxFileName metricsDir = databasePath;
461 std::vector<std::string> arguments = {
462 wxString::Format(
"--crashreporter-path=%s", crashreporterPath.GetFullPath()).ToUTF8().data(),
463#if defined(CRASH_REPORT_URL)
465 "--crashreporter-argument=-u=%s",
466 CRASH_REPORT_URL).ToUTF8().data(),
468 "--crashreporter-argument=-a=version=\"%s\",sentry[release]=\"%s\"",
469 AUDACITY_VERSION_STRING,
470 sentryRelease).ToUTF8().data()
480 catch (std::exception& e)
482 wxLogError(
"Crashpad init error: %s", e.what());
486#elif !defined(_DEBUG)
487#if defined(HAS_CRASH_REPORT)
488#if defined(wxUSE_ON_FATAL_EXCEPTION) && wxUSE_ON_FATAL_EXCEPTION
489 wxHandleFatalExceptions();
535 wxTheApp->SetExitOnFrameDelete(
true);
567#ifdef EXPERIMENTAL_SCOREALIGN
568 CloseScoreAlignDialog();
574 #if !defined(__WXMAC__)
588 logger->SaveLog(logFile.GetFullPath());
592 std::unique_ptr<wxLog>{ wxLog::SetActiveTarget(NULL) };
605#if defined(__WXGTK__) && defined(HAVE_GTK)
625#include <glib-object.h>
627typedef struct _GnomeProgram GnomeProgram;
628typedef struct _GnomeModuleInfo GnomeModuleInfo;
629typedef struct _GnomeClient GnomeClient;
641 GNOME_INTERACT_ERRORS,
651typedef GnomeProgram * (*_gnome_program_init_fn)(
const char *,
653 const GnomeModuleInfo *,
658typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
659typedef GnomeClient * (*_gnome_master_client_fn)(void);
660typedef void (*GnomeInteractFunction)(GnomeClient *,
664typedef void (*_gnome_client_request_interaction_fn)(GnomeClient *,
666 GnomeInteractFunction,
668typedef void (*_gnome_interaction_key_return_fn)(gint, gboolean);
670static _gnome_client_request_interaction_fn gnome_client_request_interaction;
671static _gnome_interaction_key_return_fn gnome_interaction_key_return;
673static void interact_cb(GnomeClient * ,
678 wxCloseEvent e(wxEVT_QUERY_END_SESSION, wxID_ANY);
684 gnome_interaction_key_return(
key, e.GetVeto());
687static gboolean save_yourself_cb(GnomeClient *client,
691 GnomeInteractStyle interact,
695 if (!shutdown || interact != GNOME_INTERACT_ANY) {
703 gnome_client_request_interaction(client,
717 const char *libgnomeui =
"libgnomeui-2.so";
718 const char *libgnome =
"libgnome-2.so";
720 const char *libgnomeui =
"libgnomeui-2.so.0";
721 const char *libgnome =
"libgnome-2.so.0";
724 mArgv[0].reset(strdup(
"Audacity"));
726 mGnomeui = dlopen(libgnomeui, RTLD_NOW);
731 mGnome = dlopen(libgnome, RTLD_NOW);
736 _gnome_program_init_fn gnome_program_init = (_gnome_program_init_fn)
737 dlsym(mGnome,
"gnome_program_init");
738 _libgnomeui_module_info_get_fn libgnomeui_module_info_get = (_libgnomeui_module_info_get_fn)
739 dlsym(mGnomeui,
"libgnomeui_module_info_get");
740 _gnome_master_client_fn gnome_master_client = (_gnome_master_client_fn)
741 dlsym(mGnomeui,
"gnome_master_client");
743 gnome_client_request_interaction = (_gnome_client_request_interaction_fn)
744 dlsym(mGnomeui,
"gnome_client_request_interaction");
745 gnome_interaction_key_return = (_gnome_interaction_key_return_fn)
746 dlsym(mGnomeui,
"gnome_interaction_key_return");
749 if (!gnome_program_init || !libgnomeui_module_info_get) {
753 gnome_program_init(mArgv[0].get(),
755 libgnomeui_module_info_get(),
757 reinterpret_cast<char**
>(mArgv),
760 mClient = gnome_master_client();
761 if (mClient == NULL) {
765 g_signal_connect(mClient,
"save-yourself", G_CALLBACK(save_yourself_cb), NULL);
768 virtual ~GnomeShutdown()
778 GnomeClient *mClient;
783GnomeShutdown GnomeShutdownInstance;
796#define IPC_APPL wxT("audacity")
797#define IPC_TOPIC wxT("System")
811 bool OnExec(
const wxString & WXUNUSED(topic),
812 const wxString & data)
846#if defined(__WXMAC__)
851#include <ApplicationServices/ApplicationServices.h>
860 wxDISABLE_DEBUG_SUPPORT();
868 ProcessSerialNumber psn = { 0, kCurrentProcess };
869 TransformProcessType(&psn, kProcessTransformToUIElementApplication);
875#elif defined(__WXGTK__) && defined(NDEBUG)
887 wxDISABLE_DEBUG_SUPPORT();
894 freopen(
"/dev/null",
"w", stdout);
895 freopen(
"/dev/null",
"w", stderr);
900#elif defined(__WXGTK__)
904wxIMPLEMENT_WX_THEME_SUPPORT
910 wxDISABLE_DEBUG_SUPPORT();
918wxIMPLEMENT_WX_THEME_SUPPORT
919extern "C" int WINAPI WinMain(HINSTANCE hInstance,
920 HINSTANCE hPrevInstance,
921 wxCmdLineArgType lpCmdLine,
924 static CommandLineArgs::MSWParser wxArgs;
928 wxDISABLE_DEBUG_SUPPORT();
930 return wxEntry(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
963#ifdef HAS_CUSTOM_URL_HANDLING
964void AudacityApp::MacOpenURL (
const wxString& url)
967 ofqueue.push_back(urlPrefix + url);
974#define ID_IPC_SERVER 6200
975#define ID_IPC_SOCKET 6201
978#define kAudacityAppTimerID 0
1026 auto proj = pProj.get();
1028 if (!fullPathStr.empty())
1031 if (wxFile::Exists(fullPathStr))
1050"%s could not be found.\n\nIt has been removed from the list of recent files.")
1060 return GuardedCall< bool >( [&]{
return MRUOpen( fullPathStr ); } );
1074 const auto &fullPathStr = history[ n ];
1108 window.RequestUserAttention();
1113 #ifdef HAS_CUSTOM_URL_HANDLING
1114 if (
name.StartsWith(urlPrefix))
1116 const auto utf8Url =
name.ToUTF8();
1117 const size_t prefixSize = urlPrefix.Length();
1119 if (utf8Url.length() <= prefixSize)
1123 { utf8Url.data() + prefixSize,
1124 utf8Url.length() - prefixSize });
1139 wxLogMessage(
wxT(
"MRUOpen failed"));
1146#if defined(__WXMSW__)
1147#define WL(lang, sublang) (lang), (sublang),
1149#define WL(lang,sublang)
1152#if wxCHECK_VERSION(3, 0, 1) && !wxCHECK_VERSION(3, 1, 6)
1153wxLanguageInfo userLangs[] =
1156 { wxLANGUAGE_USER_DEFINED,
wxT(
"eu"),
WL(0, SUBLANG_DEFAULT)
wxT(
"Basque"), wxLayout_LeftToRight },
1162#if defined(HAS_CRASH_REPORT)
1163 CrashReport::Generate(wxDebugReport::Context_Exception);
1172#pragma warning( push )
1173#pragma warning( disable : 4702)
1190 auto pException = std::current_exception();
1204 try { std::rethrow_exception( pException ); }
1216 return wxApp::OnExceptionInMainLoop();
1222#pragma warning( pop )
1243 wxConfigBase::Set(
nullptr);
1269 -> std::unique_ptr<BasicUI::WindowPlacement> {
1270 return std::make_unique<wxWidgetsWindowPlacement>(
1279 XO(
"SQLite library failed to initialize. Audacity cannot continue.") );
1287#if defined(__WXMAC__)
1289 wxSystemOptions::SetOption(wxMAC_WINDOW_PLAIN_TRANSITION, 1);
1295#if defined(__WXGTK3__) && defined(HAVE_GTK)
1296 GtkWidget *combo = gtk_combo_box_new();
1297 GtkCssProvider *provider = gtk_css_provider_new();
1298 gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
1301 ".linked combobox box.linked button,\n"
1302 ".horizontal.linked entry,\n"
1303 ".horizontal.linked button,\n"
1304 ".horizontal.linked combobox box.linked button,\n"
1306 " padding-top: 0px;\n"
1307 " padding-bottom: 0px;\n"
1308 " padding-left: 4px;\n"
1309 " padding-right: 4px;\n"
1311 " font-size: 95%;\n"
1313 gtk_style_context_add_provider_for_screen(gtk_widget_get_screen(combo),
1314 GTK_STYLE_PROVIDER (provider),
1315 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1316 g_object_unref(provider);
1317 g_object_unref(combo);
1318#elif defined(__WXGTK__) && defined(HAVE_GTK)
1319 gtk_rc_parse_string(
"style \"audacity\" {\n"
1320 " GtkButton::inner_border = { 0, 0, 0, 0 }\n"
1321 " GtkEntry::inner_border = { 0, 0, 0, 0 }\n"
1325 "widget_class \"*GtkCombo*\" style \"audacity\"");
1328 wxTheApp->SetAppName(
AppName);
1330 wxTheApp->SetAppDisplayName(
AppName);
1331 wxTheApp->SetVendorName(
AppName);
1333 ::wxInitAllImageHandlers();
1336 wxFileSystem::AddHandler(
safenew wxZipFSHandler);
1354 wxEventLoopGuarantor eventLoop;
1365#if wxCHECK_VERSION(3, 0, 1) && !wxCHECK_VERSION(3, 1, 6)
1366 for (
size_t i = 0, cnt = WXSIZEOF(userLangs); i < cnt; i++)
1368 wxLocale::AddLanguage(userLangs[i]);
1407 using namespace std::chrono;
1410 std::this_thread::sleep_for(100ms);
1423#if defined(__WXMAC__)
1424 SetExitOnFrameDelete(
false);
1430 PreferenceKey(FileNames::Operation::Temp, FileNames::PathType::_None);
1451 return std::make_unique<SettingsWX>(
1466 wxString journalFileName;
1467 const bool playingJournal = parser->Found(
"j", &journalFileName);
1469#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
1470 if (!playingJournal)
1474 if (parser->Found(
wxT(
"v")))
1476 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
1481 if (parser->Found(
wxT(
"b"), &lval))
1483 if (lval < 256 || lval > 100000000)
1485 wxPrintf(
_(
"Block size must be within 256 to 100000000\n"));
1496 wxImage logoimage((
const char **)Audacity_splash_xpm);
1497 logoimage.Scale(logoimage.GetWidth() * (2.0/3.0), logoimage.GetHeight() * (2.0/3.0), wxIMAGE_QUALITY_HIGH);
1498 if( GetLayoutDirection() == wxLayout_RightToLeft)
1499 logoimage = logoimage.Mirror();
1500 wxBitmap logo(logoimage);
1507 bool bMaximized =
false;
1508 bool bIconized =
false;
1511 wxSplashScreen temporarywindow(
1513 wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT,
1517 wndRect.GetTopLeft(),
1529 temporarywindow.SetPosition( wndRect.GetTopLeft() );
1531 temporarywindow.Center();
1532 temporarywindow.SetTitle(
_(
"Audacity is starting up..."));
1533 SetTopWindow(&temporarywindow);
1534 temporarywindow.Raise();
1538 wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
1552 auto fileMenu = std::make_unique<wxMenu>();
1553 auto urecentMenu = std::make_unique<wxMenu>();
1554 auto recentMenu = urecentMenu.get();
1555 fileMenu->Append(wxID_NEW, wxString(
_(
"&New")) +
wxT(
"\tCtrl+N"));
1556 fileMenu->Append(wxID_OPEN, wxString(
_(
"&Open...")) +
wxT(
"\tCtrl+O"));
1557 fileMenu->AppendSubMenu(urecentMenu.release(),
_(
"Open &Recent..."));
1558 fileMenu->Append(wxID_ABOUT,
_(
"&About Audacity..."));
1559 fileMenu->Append(wxID_PREFERENCES, wxString(
_(
"&Preferences...")) +
wxT(
"\tCtrl+,"));
1562 auto menuBar = std::make_unique<wxMenuBar>();
1563 menuBar->Append(fileMenu.release(),
_(
"&File"));
1567 wxMenuBar::MacSetCommonMenuBar(menuBar.release());
1571 recentFiles.UseMenu(recentMenu);
1574 temporarywindow.Show(
false);
1578 std::vector<wxString> failedPlugins;
1582 if(!newPlugins.empty())
1586 failedPlugins =
reg.GetFailedPluginsPaths();
1616#if defined(HAVE_UPDATES_CHECK)
1626 int vMajorInit, vMinorInit, vMicroInit;
1628 if (vMajorInit != AUDACITY_VERSION || vMinorInit != AUDACITY_RELEASE
1629 || vMicroInit != AUDACITY_REVISION) {
1635 bool didRecoverAnything =
false;
1637 if (!playingJournal)
1648 if (
project && !didRecoverAnything)
1650 if (parser->Found(
wxT(
"t")))
1656 for (
size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
1663 if(!failedPlugins.empty())
1666 dialog->Bind(wxEVT_CLOSE_WINDOW, [dialog](wxCloseEvent&) { dialog->Destroy(); });
1679#ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS
1682 if (::wxGetMouseState().ShiftDown()) {
1699#if defined(__WXMAC__)
1707 bool permsReset =
false;
1708 gPrefs->
Read(
wxT(
"/MicrophonePermissionsReset"), &permsReset,
false);
1710 system(
"tccutil reset Microphone org.audacityteam.audacity");
1715#if defined(__WXMAC__)
1717 Bind(wxEVT_MENU_OPEN, [=](wxMenuEvent &event)
1719 wxSetlocale(LC_NUMERIC, wxString(
wxT(
"C")));
1723 Bind(wxEVT_MENU_CLOSE, [=](wxMenuEvent &event)
1730#ifdef HAS_CUSTOM_URL_HANDLING
1735 if (parser->Found(
"u", &url))
1737 auto utf8Url = url.ToUTF8();
1750 auto result = wxApp::OnRun();
1790 if(event.GetKeyCode() == WXK_ESCAPE) {
1795 auto scrubbing = scrubber.HasMark();
1800 gAudioIO->IsAudioTokenActive(token) &&
1801 gAudioIO->GetNumCaptureChannels() == 0) ||
1819 if( wxDirExists( dir ) ){
1824 wxFileName
name( dir +
"/junkname.cfg" );
1825 if(
name.Mkdir( wxS_DIR_DEFAULT , wxPATH_MKDIR_FULL ) )
1838 if (tempFromPrefs.length() > 0 && tempFromPrefs[0] !=
wxT(
'/'))
1839 tempFromPrefs =
wxT(
"");
1857 struct stat tempStatBuf;
1858 if ( lstat(temp.mb_str(), &tempStatBuf) != 0 ) {
1862 if ( geteuid() != tempStatBuf.st_uid ) {
1872"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."));
1875"Audacity could not find a place to store temporary files.\nPlease enter an appropriate directory in the preferences dialog."));
1885"Audacity is now going to exit. Please launch Audacity again to use the new temporary directory."));
1901#if defined(__WXMSW__)
1908 wxString
name = wxString::Format(
wxT(
"audacity-lock-%s"), wxGetUserId());
1910 auto checker = std::make_unique<wxSingleInstanceChecker>();
1912 auto runningTwoCopiesStr =
XO(
"Running two copies of Audacity simultaneously may cause\ndata loss or cause your system to crash.\n\n");
1914 if (!checker->Create(
name, dir))
1920"Audacity was not able to lock the temporary files directory.\nThis folder may be in use by another copy of Audacity.\n")
1921 + runningTwoCopiesStr
1922 +
XO(
"Do you still want to start Audacity?");
1925 XO(
"Error Locking Temporary Folder"),
1926 wxYES_NO | wxICON_EXCLAMATION, NULL);
1930 else if ( checker->IsAnotherRunning() ) {
1940 if (parser->Found(
wxT(
"v")))
1942 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
1949 for (
size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
1951 wxFileName filename(parser->GetParam(i));
1952 if (filename.MakeAbsolute())
1954 filenames.push_back(filename.GetLongPath());
1958 #ifdef HAS_CUSTOM_URL_HANDLING
1960 parser->Found(
"u", &url);
1972 for (
int i = 0; i < 50; i++)
1974 std::unique_ptr<wxConnectionBase> conn{ client.MakeConnection(wxEmptyString,
IPC_APPL,
IPC_TOPIC) };
1978 #ifdef HAS_CUSTOM_URL_HANDLING
1981 if (!conn->Execute(urlPrefix + url))
1986 if (filenames.size() > 0)
1988 for (
size_t i = 0, cnt = filenames.size(); i < cnt; i++)
1990 ok = conn->Execute(filenames[i]);
1996 ok = conn->Execute(wxEmptyString);
2003 using namespace std::chrono;
2004 std::this_thread::sleep_for(10ms);
2009"The system has detected that another copy of Audacity is running.\n")
2010 + runningTwoCopiesStr
2012"Use the New or Open commands in the currently running Audacity\nprocess to open multiple projects simultaneously.\n");
2014 prompt,
XO(
"Audacity is already running"),
2015 wxOK | wxICON_ERROR);
2027#if defined(__UNIX__)
2040 bool isServer =
false;
2044 struct sembuf op = {};
2048 key_t memkey = ftok(datadir.c_str(), 0);
2049 key_t servkey = ftok(datadir.c_str(), 1);
2050 key_t lockkey = ftok(datadir.c_str(), 2);
2054 int memid = shmget(memkey,
sizeof(
int), IPC_CREAT | S_IRUSR | S_IWUSR);
2058 XO(
"Unable to create shared memory segment.\n\n"
2059 "error code=%d : \"%s\".").
Format(errno, strerror(errno)),
2060 XO(
"Audacity Startup Failure"),
2061 wxOK | wxICON_ERROR);
2066 int *portnum = (
int *) shmat(memid,
nullptr, 0);
2069 int servid = semget(servkey, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
2072 int lockid = semget(lockkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
2085 semctl(servid, 0, SETVAL, 1);
2086 semctl(lockid, 0, SETVAL, 1);
2092 op.sem_flg = SEM_UNDO;
2093 if (semop(lockid, &op, 1) == -1 || semop(servid, &op, 1) == -1)
2096 XO(
"Unable to acquire semaphores.\n\n"
2097 "This is likely due to a resource shortage\n"
2098 "and a reboot may be required."),
2099 XO(
"Audacity Startup Failure"),
2100 wxOK | wxICON_ERROR);
2109 else if (errno != EEXIST)
2112 XO(
"Unable to create semaphores.\n\n"
2113 "This is likely due to a resource shortage\n"
2114 "and a reboot may be required."),
2115 XO(
"Audacity Startup Failure"),
2116 wxOK | wxICON_ERROR);
2125 lockid = semget(lockkey, 1, 0);
2131 op.sem_flg = SEM_UNDO;
2132 if (semop(lockid, &op, 1) == -1)
2135 XO(
"Unable to acquire lock semaphore.\n\n"
2136 "This is likely due to a resource shortage\n"
2137 "and a reboot may be required."),
2138 XO(
"Audacity Startup Failure"),
2139 wxOK | wxICON_ERROR);
2149 op.sem_flg = IPC_NOWAIT | SEM_UNDO;
2150 if (semop(servid, &op, 1) == 0)
2154 else if (errno != EAGAIN)
2157 XO(
"Unable to acquire server semaphore.\n\n"
2158 "This is likely due to a resource shortage\n"
2159 "and a reboot may be required."),
2160 XO(
"Audacity Startup Failure"),
2161 wxOK | wxICON_ERROR);
2174 auto serv = std::make_unique<wxSocketServer>(addr, wxSOCKET_NOWAIT);
2175 if (serv && serv->IsOk())
2178 serv->SetNotify(wxSOCKET_CONNECTION_FLAG);
2185 *portnum = addr.Service();
2194 semop(lockid, &op, 1);
2200 XO(
"The Audacity IPC server failed to initialize.\n\n"
2201 "This is likely due to a resource shortage\n"
2202 "and a reboot may be required."),
2203 XO(
"Audacity Startup Failure"),
2204 wxOK | wxICON_ERROR);
2215 addr.Service(*portnum);
2220 semop(lockid, &op, 1);
2231 sock->SetFlags(wxSOCKET_WAITALL);
2234 sock->Connect(addr,
true);
2235 if (!sock->IsConnected())
2241 XO(
"An unrecoverable error has occurred during startup"),
2242 XO(
"Audacity Startup Failure"),
2243 wxOK | wxICON_ERROR);
2258 if (parser->Found(
wxT(
"v")))
2260 wxPrintf(
"Audacity v%s\n", AUDACITY_VERSION_STRING);
2265#ifdef HAS_CUSTOM_URL_HANDLING
2268 if (parser->Found(
wxT(
"u"), &url))
2272 url = urlPrefix + url;
2273 auto str = url.c_str().AsWChar();
2275 sock->WriteMsg(
str, (url.length() + 1) *
sizeof(*
str));
2280#if defined(__WXMAC__)
2284 for (
const auto &filename:
ofqueue)
2286 auto str = filename.c_str().AsWChar();
2287 sock->WriteMsg(
str, (filename.length() + 1) *
sizeof(*
str));
2293 for (
size_t j = 0, cnt = parser->GetParamCount(); j < cnt; ++j)
2295 wxFileName filename(parser->GetParam(j));
2296 if (filename.MakeAbsolute())
2298 const wxString param = filename.GetLongPath();
2299 sock->WriteMsg((
const wxChar *) param, (param.length() + 1) *
sizeof(wxChar));
2304 sock->WriteMsg(wxEmptyString,
sizeof(wxChar));
2323 sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
2331 wxSocketBase *sock = evt.GetSocket();
2333 if (evt.GetSocketEvent() == wxSOCKET_LOST)
2340 wxChar
name[PATH_MAX];
2341 sock->ReadMsg(&
name,
sizeof(
name));
2354 auto parser = std::make_unique<wxCmdLineParser>(
argc,
argv);
2362 parser->AddOption(
wxT(
"b"),
wxT(
"blocksize"),
_(
"set max disk block size in bytes"),
2363 wxCMD_LINE_VAL_NUMBER);
2365 const auto journalOptionDescription =
2369 _(
"replay a journal file");
2371 parser->AddOption(
wxT(
"j"),
wxT(
"journal"), journalOptionDescription);
2374 parser->AddSwitch(
wxT(
"h"),
wxT(
"help"),
_(
"this help message"),
2375 wxCMD_LINE_OPTION_HELP);
2378 parser->AddSwitch(
wxT(
"t"),
wxT(
"test"),
_(
"run self diagnostics"));
2381 parser->AddSwitch(
wxT(
"v"),
wxT(
"version"),
_(
"display Audacity version"));
2385 parser->AddParam(
_(
"audio or project file name"),
2386 wxCMD_LINE_VAL_STRING,
2387 wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL);
2389#ifdef HAS_CUSTOM_URL_HANDLING
2391 parser->AddOption(
wxT(
"u"),
wxT(
"url"),
_(
"Handle 'audacity://' url"));
2395 if (parser->Parse() == 0)
2403 bool mustVeto =
false;
2406 mustVeto = wxDialog::OSXHasModalDialogsOpen();
2417 bool force = !
event.CanVeto();
2448 bool bFalse =
false;
2464#ifdef HAS_NETWORKING
2586#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
2590 bool bWantAssociateFiles =
true;
2591 if (
gPrefs->
Read(
wxT(
"/WantAssociateFiles"), &bWantAssociateFiles) &&
2592 !bWantAssociateFiles)
2598 wxRegKey associateFileTypes;
2600 auto IsDefined = [&](
const wxString &type)
2602 associateFileTypes.SetName(wxString::Format(
wxT(
"HKCR\\%s"), type));
2603 bool bKeyExists = associateFileTypes.Exists();
2607 associateFileTypes.SetName(wxString::Format(
wxT(
"HKCU\\Software\\Classes\\%s"), type));
2608 bKeyExists = associateFileTypes.Exists();
2613 auto DefineType = [&](
const wxString &type)
2615 wxString root_key =
wxT(
"HKCU\\Software\\Classes\\");
2618 associateFileTypes.SetName(wxString::Format(
wxT(
"%s%s"), root_key, type));
2619 if (!associateFileTypes.Create(
true))
2622 root_key =
wxT(
"HKCR\\");
2623 associateFileTypes.SetName(wxString::Format(
wxT(
"%s%s"), root_key, type));
2624 if (!associateFileTypes.Create(
true))
2631 if (!root_key.empty())
2633 associateFileTypes =
wxT(
"Audacity.Project");
2640 if (IsDefined(
wxT(
".aup3")) && IsDefined(
wxT(
".aup")) && IsDefined(
wxT(
"Audacity.Project")))
2650"Audacity project (.aup3) files are not currently \nassociated with Audacity. \n\nAssociate them, so they open on double-click?"),
2651 XO(
"Audacity Project Files"),
2652 wxYES_NO | wxICON_QUESTION);
2654 if (wantAssoc == wxNO)
2668 root_key = DefineType(
wxT(
".aup3"));
2669 if (root_key.empty())
2675 DefineType(
wxT(
".aup"));
2677 associateFileTypes =
wxT(
"Audacity.Project");
2678 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project"));
2679 if (!associateFileTypes.Exists())
2681 associateFileTypes.Create(
true);
2682 associateFileTypes =
wxT(
"Audacity Project File");
2685 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell"));
2686 if (!associateFileTypes.Exists())
2688 associateFileTypes.Create(
true);
2689 associateFileTypes =
wxT(
"");
2692 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open"));
2693 if (!associateFileTypes.Exists())
2695 associateFileTypes.Create(
true);
2698 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\command"));
2699 wxString tmpRegAudPath;
2700 if(associateFileTypes.Exists())
2702 tmpRegAudPath = associateFileTypes.QueryDefaultValue().Lower();
2705 if (!associateFileTypes.Exists() ||
2706 (tmpRegAudPath.Find(
wxT(
"audacity.exe")) >= 0))
2708 associateFileTypes.Create(
true);
2709 associateFileTypes = (wxString)
argv[0] + (wxString)
wxT(
" \"%1\"");
2716 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec"));
2717 if (!associateFileTypes.Exists())
2719 associateFileTypes.Create(
true);
2720 associateFileTypes =
wxT(
"%1");
2723 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec\\Application"));
2724 if (!associateFileTypes.Exists())
2726 associateFileTypes.Create(
true);
2730 associateFileTypes.SetName(root_key +
wxT(
"Audacity.Project\\shell\\open\\ddeexec\\Topic"));
2731 if (!associateFileTypes.Exists())
2733 associateFileTypes.Create(
true);
2743 static std::once_flag configSetupFlag;
2744 std::call_once(configSetupFlag, [&]{
2747 wxTheApp->GetAppName(), wxEmptyString,
2748 configFileName.GetFullPath(),
2749 wxEmptyString, wxCONFIG_USE_LOCAL_FILE);
2750 wxConfigBase::Set(
gConfig.get());
2752 return std::make_unique<SettingsWX>(
gConfig);
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 std::shared_ptr< wxConfigBase > gConfig
static wxArrayString ofqueue
static audacity::ApplicationSettings::Scope applicationSettingsScope
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
bool ShowAutoRecoveryDialogIfNeeded(AudacityProject *&pproj, bool *didRecoverAnything)
void RunBenchmark(wxWindow *parent, AudacityProject &project)
Contains declarations for the CommandHandler class.
PrefsPanel::Factory DirectoriesPrefsFactory()
const TranslatableString name
BoolSetting SkipEffectsScanAtStartup
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.
void HandleAppInitialized()
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 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 PendingTracks & Get(AudacityProject &project)
void ClearPendingTracks(std::vector< std::shared_ptr< Track > > *pAdded=nullptr)
Forget pending track additions and changes;.
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 Scrubber & Get(AudacityProject &project)
static void SetMaxDiskBlockSize(size_t bytes)
bool Read(T *pVar) const
overload of Read returning a boolean that is true if the value was previously defined */
static void DoHelpWelcome(AudacityProject &project)
static bool LoadPreferredTheme()
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 Viewport & Get(AudacityProject &project)
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.
IMPORT_EXPORT_API 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
static CommandContext::TargetFactory::SubstituteInUnique< InteractiveOutputTargets > scope
std::string ToUTF8(const std::wstring &wstr)