Audacity  3.0.3
AudacityApp.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  AudacityApp.cpp
6 
7  Dominic Mazzoni
8 
9 ******************************************************************//*******************************************************************/
17 
18 
19 #include "AudacityApp.h"
20 
21 
22 
23 #if 0
24 // This may be used to debug memory leaks.
25 // See: Visual Leak Detector @ http://vld.codeplex.com/
26 #include <vld.h>
27 #endif
28 
29 #include <wx/setup.h> // for wxUSE_* macros
30 #include <wx/wxcrtvararg.h>
31 #include <wx/defs.h>
32 #include <wx/evtloop.h>
33 #include <wx/app.h>
34 #include <wx/bitmap.h>
35 #include <wx/docview.h>
36 #include <wx/event.h>
37 #include <wx/ipc.h>
38 #include <wx/window.h>
39 #include <wx/intl.h>
40 #include <wx/menu.h>
41 #include <wx/snglinst.h>
42 #include <wx/splash.h>
43 #include <wx/stdpaths.h>
44 #include <wx/sysopt.h>
45 #include <wx/fontmap.h>
46 
47 #include <wx/fs_zip.h>
48 #include <wx/image.h>
49 
50 #include <wx/dir.h>
51 #include <wx/file.h>
52 #include <wx/filename.h>
53 
54 #ifdef __WXGTK__
55 #include <unistd.h>
56 #ifdef HAVE_GTK
57 #include <gtk/gtk.h>
58 #endif
59 #endif
60 
61 // chmod, lstat, geteuid
62 #ifdef __UNIX__
63 #include <sys/types.h>
64 #include <sys/file.h>
65 #include <sys/stat.h>
66 #include <stdio.h>
67 #endif
68 
69 #if defined(__WXMSW__)
70 #include <wx/msw/registry.h> // for wxRegKey
71 #endif
72 
73 #include "AudacityLogger.h"
74 #include "AboutDialog.h"
75 #include "ActiveProject.h"
76 #include "AColor.h"
77 #include "AudacityFileConfig.h"
78 #include "AudioIO.h"
79 #include "Benchmark.h"
80 #include "Clipboard.h"
81 #include "CrashReport.h" // for HAS_CRASH_REPORT
84 #include "widgets/ASlider.h"
85 #include "FFmpeg.h"
86 #include "Journal.h"
87 //#include "LangChoice.h"
88 #include "Languages.h"
89 #include "Menus.h"
90 #include "PluginManager.h"
91 #include "Project.h"
92 #include "ProjectAudioIO.h"
93 #include "ProjectAudioManager.h"
94 #include "ProjectFileIO.h"
95 #include "ProjectFileManager.h"
96 #include "ProjectHistory.h"
97 #include "ProjectManager.h"
98 #include "ProjectSettings.h"
99 #include "ProjectWindow.h"
100 #include "ProjectWindows.h"
101 #include "Screenshot.h"
102 #include "Sequence.h"
103 #include "SelectFile.h"
104 #include "TempDirectory.h"
105 #include "Track.h"
106 #include "prefs/PrefsDialog.h"
107 #include "Theme.h"
108 #include "PlatformCompatibility.h"
109 #include "AutoRecoveryDialog.h"
110 #include "SplashDialog.h"
111 #include "FFT.h"
113 #include "prefs/DirectoriesPrefs.h"
114 #include "prefs/GUIPrefs.h"
115 #include "tracks/ui/Scrubbing.h"
116 #include "FileConfig.h"
117 #include "widgets/FileHistory.h"
118 #include "update/UpdateManager.h"
120 
121 #ifdef HAS_NETWORKING
122 #include "NetworkManager.h"
123 #endif
124 
125 #ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS
126 #include "prefs/KeyConfigPrefs.h"
127 #endif
128 
129 //temporarily commented out till it is added to all projects
130 //#include "Profiler.h"
131 
132 #include "ModuleManager.h"
133 
134 #include "import/Import.h"
135 
136 #if defined(USE_BREAKPAD)
137 #include "BreakpadConfigurer.h"
138 #endif
139 
140 #ifdef EXPERIMENTAL_SCOREALIGN
142 #endif
143 
144 #if 0
145 #ifdef _DEBUG
146  #ifdef _MSC_VER
147  #undef THIS_FILE
148  static char*THIS_FILE= __FILE__;
149  #define new new(_NORMAL_BLOCK, THIS_FILE, __LINE__)
150  #endif
151 #endif
152 #endif
153 
154 // DA: Logo for Splash Screen
155 #ifdef EXPERIMENTAL_DA
156 #include "../images/DarkAudacityLogoWithName.xpm"
157 #else
158 #include "../images/AudacityLogoWithName.xpm"
159 #endif
160 
161 #include <thread>
162 
163 
167 
168 #if 0
169 #ifdef __WXGTK__
170 static void wxOnAssert(const wxChar *fileName, int lineNumber, const wxChar *msg)
171 {
172  if (msg)
173  wxPrintf("ASSERTION FAILED: %s\n%s: %d\n", (const char *)wxString(msg).mb_str(), (const char *)wxString(fileName).mb_str(), lineNumber);
174  else
175  wxPrintf("ASSERTION FAILED!\n%s: %d\n", (const char *)wxString(fileName).mb_str(), lineNumber);
176 
177  // Force core dump
178  int *i = 0;
179  if (*i)
180  exit(1);
181 
182  exit(0);
183 }
184 #endif
185 #endif
186 
187 namespace {
188 
190 {
191  bool resetPrefs = false;
192  wxString langCode = gPrefs->Read(wxT("/Locale/Language"), wxEmptyString);
193  bool writeLang = false;
194 
195  const wxFileName fn(
197  wxT("FirstTime.ini"));
198  if (fn.FileExists()) // it will exist if the (win) installer put it there
199  {
200  const wxString fullPath{fn.GetFullPath()};
201 
202  auto pIni =
203  AudacityFileConfig::Create({}, {}, fullPath, {},
204  wxCONFIG_USE_LOCAL_FILE);
205  auto &ini = *pIni;
206 
207  wxString lang;
208  if (ini.Read(wxT("/FromInno/Language"), &lang) && !lang.empty())
209  {
210  // Only change "langCode" if the language was actually specified in the ini file.
211  langCode = lang;
212  writeLang = true;
213 
214  // Inno Setup doesn't allow special characters in the Name values, so "0" is used
215  // to represent the "@" character.
216  langCode.Replace(wxT("0"), wxT("@"));
217  }
218 
219  ini.Read(wxT("/FromInno/ResetPrefs"), &resetPrefs, false);
220 
221  bool gone = wxRemoveFile(fullPath); // remove FirstTime.ini
222  if (!gone)
223  {
225  XO("Failed to remove %s").Format(fullPath),
226  XO("Failed!"));
227  }
228  }
229 
230  // Use the system default language if one wasn't specified or if the user selected System.
231  if (langCode.empty())
232  langCode =
234 
235  langCode = GUIPrefs::SetLang( langCode );
236 
237  // User requested that the preferences be completely reset
238  if (resetPrefs)
239  {
240  // pop up a dialogue
241  auto prompt = XO(
242 "Reset Preferences?\n\nThis is a one-time question, after an 'install' where you asked to have the Preferences reset.");
243  int action = AudacityMessageBox(
244  prompt,
245  XO("Reset Audacity Preferences"),
246  wxYES_NO, NULL);
247  if (action == wxYES) // reset
248  {
250  writeLang = true;
251  }
252  }
253 
254  // Save the specified language
255  if (writeLang)
256  {
257  gPrefs->Write(wxT("/Locale/Language"), langCode);
258  }
259 
260  // In AUdacity 2.1.0 support for the legacy 1.2.x preferences (depreciated since Audacity
261  // 1.3.1) is dropped. As a result we can drop the import flag
262  // first time this version of Audacity is run we try to migrate
263  // old preferences.
264  bool newPrefsInitialized = false;
265  gPrefs->Read(wxT("/NewPrefsInitialized"), &newPrefsInitialized, false);
266  if (newPrefsInitialized) {
267  gPrefs->DeleteEntry(wxT("/NewPrefsInitialized"), true); // take group as well if empty
268  }
269 
270  // record the Prefs version for future checking (this has not been used for a very
271  // long time).
272  gPrefs->Write(wxT("/PrefsVersion"), wxString(wxT(AUDACITY_PREFS_VERSION_STRING)));
273 
274  // Check if some prefs updates need to happen based on audacity version.
275  // Unfortunately we can't use the PrefsVersion prefs key because that resets things.
276  // In the future we may want to integrate that better.
277  // these are done on a case-by-case basis for now so they must be backwards compatible
278  // (meaning the changes won't mess audacity up if the user goes back to an earlier version)
279  int vMajor = gPrefs->Read(wxT("/Version/Major"), (long) 0);
280  int vMinor = gPrefs->Read(wxT("/Version/Minor"), (long) 0);
281  int vMicro = gPrefs->Read(wxT("/Version/Micro"), (long) 0);
282 
283  gPrefs->SetVersionKeysInit(vMajor, vMinor, vMicro); // make a note of these initial values
284  // for use by ToolManager::ReadConfig()
285 
286  // These integer version keys were introduced april 4 2011 for 1.3.13
287  // The device toolbar needs to be enabled due to removal of source selection features in
288  // the mixer toolbar.
289  if ((vMajor < 1) ||
290  (vMajor == 1 && vMinor < 3) ||
291  (vMajor == 1 && vMinor == 3 && vMicro < 13)) {
292 
293 
294  // Do a full reset of the Device Toolbar to get it on the screen.
295  if (gPrefs->Exists(wxT("/GUI/ToolBars/Device")))
296  gPrefs->DeleteGroup(wxT("/GUI/ToolBars/Device"));
297 
298  // We keep the mixer toolbar prefs (shown/not shown)
299  // the width of the mixer toolbar may have shrunk, the prefs will keep the larger value
300  // if the user had a device that had more than one source.
301  if (gPrefs->Exists(wxT("/GUI/ToolBars/Mixer"))) {
302  // Use the default width
303  gPrefs->Write(wxT("/GUI/ToolBars/Mixer/W"), -1);
304  }
305  }
306 
307  // In 2.1.0, the Meter toolbar was split and lengthened, but strange arrangements happen
308  // if upgrading due to the extra length. So, if a user is upgrading, use the pre-2.1.0
309  // lengths, but still use the NEW split versions.
310  if (gPrefs->Exists(wxT("/GUI/ToolBars/Meter")) &&
311  !gPrefs->Exists(wxT("/GUI/ToolBars/CombinedMeter"))) {
312 
313  // Read in all of the existing values
314  long dock, order, show, x, y, w, h;
315  gPrefs->Read(wxT("/GUI/ToolBars/Meter/Dock"), &dock, -1);
316  gPrefs->Read(wxT("/GUI/ToolBars/Meter/Order"), &order, -1);
317  gPrefs->Read(wxT("/GUI/ToolBars/Meter/Show"), &show, -1);
318  gPrefs->Read(wxT("/GUI/ToolBars/Meter/X"), &x, -1);
319  gPrefs->Read(wxT("/GUI/ToolBars/Meter/Y"), &y, -1);
320  gPrefs->Read(wxT("/GUI/ToolBars/Meter/W"), &w, -1);
321  gPrefs->Read(wxT("/GUI/ToolBars/Meter/H"), &h, -1);
322 
323  // "Order" must be adjusted since we're inserting two NEW toolbars
324  if (dock > 0) {
325  wxString oldPath = gPrefs->GetPath();
326  gPrefs->SetPath(wxT("/GUI/ToolBars"));
327 
328  wxString bar;
329  long ndx = 0;
330  bool cont = gPrefs->GetFirstGroup(bar, ndx);
331  while (cont) {
332  long o;
333  if (gPrefs->Read(bar + wxT("/Order"), &o) && o >= order) {
334  gPrefs->Write(bar + wxT("/Order"), o + 2);
335  }
336  cont = gPrefs->GetNextGroup(bar, ndx);
337  }
338  gPrefs->SetPath(oldPath);
339 
340  // And override the height
341  h = 27;
342  }
343 
344  // Write the split meter bar values
345  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/Dock"), dock);
346  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/Order"), order);
347  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/Show"), show);
348  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/X"), -1);
349  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/Y"), -1);
350  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/W"), w);
351  gPrefs->Write(wxT("/GUI/ToolBars/RecordMeter/H"), h);
352  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/Dock"), dock);
353  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/Order"), order + 1);
354  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/Show"), show);
355  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/X"), -1);
356  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/Y"), -1);
357  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/W"), w);
358  gPrefs->Write(wxT("/GUI/ToolBars/PlayMeter/H"), h);
359 
360  // And hide the old combined meter bar
361  gPrefs->Write(wxT("/GUI/ToolBars/Meter/Dock"), -1);
362  }
363 
364  // Upgrading pre 2.2.0 configs we assume extended set of defaults.
365  if ((0<vMajor && vMajor < 2) ||
366  (vMajor == 2 && vMinor < 2))
367  {
368  gPrefs->Write(wxT("/GUI/Shortcuts/FullDefaults"),1);
369  }
370 
371  // Upgrading pre 2.4.0 configs, the selection toolbar is now split.
372  if ((0<vMajor && vMajor < 2) ||
373  (vMajor == 2 && vMinor < 4))
374  {
375  gPrefs->Write(wxT("/GUI/Toolbars/Selection/W"),"");
376  gPrefs->Write(wxT("/GUI/Toolbars/SpectralSelection/W"),"");
377  gPrefs->Write(wxT("/GUI/Toolbars/Time/X"),-1);
378  gPrefs->Write(wxT("/GUI/Toolbars/Time/Y"),-1);
379  gPrefs->Write(wxT("/GUI/Toolbars/Time/H"),55);
380  gPrefs->Write(wxT("/GUI/Toolbars/Time/W"),251);
381  gPrefs->Write(wxT("/GUI/Toolbars/Time/DockV2"),2);
382  gPrefs->Write(wxT("/GUI/Toolbars/Time/Dock"),2);
383  gPrefs->Write(wxT("/GUI/Toolbars/Time/Path"),"0,1");
384  gPrefs->Write(wxT("/GUI/Toolbars/Time/Show"),1);
385  }
386 
387  if (std::pair{ vMajor, vMinor } < std::pair{ 3, 1 } ) {
388  // Reset the control toolbar
389  gPrefs->Write(wxT("/GUI/Toolbars/Control/W"), -1);
390  }
391 
392  // write out the version numbers to the prefs file for future checking
393  gPrefs->Write(wxT("/Version/Major"), AUDACITY_VERSION);
394  gPrefs->Write(wxT("/Version/Minor"), AUDACITY_RELEASE);
395  gPrefs->Write(wxT("/Version/Micro"), AUDACITY_REVISION);
396 
397  gPrefs->Flush();
398 }
399 
400 #if defined(USE_BREAKPAD)
401 void InitBreakpad()
402 {
403  wxFileName databasePath;
404  databasePath.SetPath(wxStandardPaths::Get().GetUserLocalDataDir());
405  databasePath.AppendDir("crashreports");
406  databasePath.Mkdir(wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
407 
408  if(databasePath.DirExists())
409  {
410  BreakpadConfigurer configurer;
411  configurer.SetDatabasePathUTF8(databasePath.GetPath().ToUTF8().data())
412  .SetSenderPathUTF8(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath().ToUTF8().data())
413  #if defined(CRASH_REPORT_URL)
414  .SetReportURL(CRASH_REPORT_URL)
415  #endif
416  .SetParameters({
417  { "version", wxString(AUDACITY_VERSION_STRING).ToUTF8().data() }
418  })
419  .Start();
420  }
421 }
422 #endif
423 }
424 
425 static bool gInited = false;
426 static bool gIsQuitting = false;
427 
428 static bool CloseAllProjects( bool force )
429 {
431  auto cleanup = finally([]{ ProjectManager::SetClosingAll(false); });
432  while (AllProjects{}.size())
433  {
434  // Closing the project has global side-effect
435  // of deletion from gAudacityProjects
436  if ( force )
437  {
438  GetProjectFrame( **AllProjects{}.begin() ).Close(true);
439  }
440  else
441  {
442  if (! GetProjectFrame( **AllProjects{}.begin() ).Close())
443  return false;
444  }
445  }
446  return true;
447 }
448 
449 static void QuitAudacity(bool bForce)
450 {
451  // guard against recursion
452  if (gIsQuitting)
453  return;
454 
455  gIsQuitting = true;
456 
457  wxTheApp->SetExitOnFrameDelete(true);
458 
459  // Try to close each open window. If the user hits Cancel
460  // in a Save Changes dialog, don't continue.
461  // BG: unless force is true
462 
463  // BG: Are there any projects open?
464  //- if (!AllProjects{}.empty())
465 /*start+*/
466  if (AllProjects{}.empty())
467  {
468 #ifdef __WXMAC__
469  Clipboard::Get().Clear();
470 #endif
471  }
472  else
473 /*end+*/
474  {
475  if (AllProjects{}.size())
476  // PRL: Always did at least once before close might be vetoed
477  // though I don't know why that is important
479  bool closedAll = CloseAllProjects( bForce );
480  if ( !closedAll )
481  {
482  gIsQuitting = false;
483  return;
484  }
485  }
486 
488 
489 #ifdef EXPERIMENTAL_SCOREALIGN
490  CloseScoreAlignDialog();
491 #endif
493 
494  //print out profile if we have one by deleting it
495  //temporarily commented out till it is added to all projects
496  //DELETE Profiler::Instance();
497 
498  // Save last log for diagnosis
499  auto logger = AudacityLogger::Get();
500  if (logger)
501  {
502  wxFileName logFile(FileNames::DataDir(), wxT("lastlog.txt"));
503  logger->SaveLog(logFile.GetFullPath());
504  }
505 
506  //remove our logger
507  std::unique_ptr<wxLog>{ wxLog::SetActiveTarget(NULL) }; // DELETE
508 
509  if (bForce)
510  {
511  wxExit();
512  }
513 }
514 
515 static void QuitAudacity()
516 {
517  QuitAudacity(false);
518 }
519 
520 #if defined(__WXGTK__) && defined(HAVE_GTK)
521 
523 // Provide the ability to receive notification from the session manager
524 // when the user is logging out or shutting down.
525 //
526 // Most of this was taken from nsNativeAppSupportUnix.cpp from Mozilla.
528 
529 // TODO: May need updating. Is this code too obsolete (relying on Gnome2 so's) to be
530 // worth keeping anymore?
531 // CB suggests we use libSM directly ref:
532 // http://www.x.org/archive/X11R7.7/doc/libSM/SMlib.html#The_Save_Yourself_Callback
533 
534 #include <dlfcn.h>
535 /* There is a conflict between the type names used in Glib >= 2.21 and those in
536  * wxGTK (http://trac.wxwidgets.org/ticket/10883)
537  * Happily we can avoid the hack, as we only need some of the headers, not
538  * the full GTK headers
539  */
540 #include <glib-object.h>
541 
542 typedef struct _GnomeProgram GnomeProgram;
543 typedef struct _GnomeModuleInfo GnomeModuleInfo;
544 typedef struct _GnomeClient GnomeClient;
545 
546 typedef enum
547 {
548  GNOME_SAVE_GLOBAL,
549  GNOME_SAVE_LOCAL,
550  GNOME_SAVE_BOTH
551 } GnomeSaveStyle;
552 
553 typedef enum
554 {
555  GNOME_INTERACT_NONE,
556  GNOME_INTERACT_ERRORS,
557  GNOME_INTERACT_ANY
558 } GnomeInteractStyle;
559 
560 typedef enum
561 {
562  GNOME_DIALOG_ERROR,
563  GNOME_DIALOG_NORMAL
564 } GnomeDialogType;
565 
566 typedef GnomeProgram * (*_gnome_program_init_fn)(const char *,
567  const char *,
568  const GnomeModuleInfo *,
569  int,
570  char **,
571  const char *,
572  ...);
573 typedef const GnomeModuleInfo * (*_libgnomeui_module_info_get_fn)();
574 typedef GnomeClient * (*_gnome_master_client_fn)(void);
575 typedef void (*GnomeInteractFunction)(GnomeClient *,
576  gint,
577  GnomeDialogType,
578  gpointer);
579 typedef void (*_gnome_client_request_interaction_fn)(GnomeClient *,
580  GnomeDialogType,
581  GnomeInteractFunction,
582  gpointer);
583 typedef void (*_gnome_interaction_key_return_fn)(gint, gboolean);
584 
585 static _gnome_client_request_interaction_fn gnome_client_request_interaction;
586 static _gnome_interaction_key_return_fn gnome_interaction_key_return;
587 
588 static void interact_cb(GnomeClient * /* client */,
589  gint key,
590  GnomeDialogType /* type */,
591  gpointer /* data */)
592 {
593  wxCloseEvent e(wxEVT_QUERY_END_SESSION, wxID_ANY);
594  e.SetEventObject(&wxGetApp());
595  e.SetCanVeto(true);
596 
597  wxGetApp().ProcessEvent(e);
598 
599  gnome_interaction_key_return(key, e.GetVeto());
600 }
601 
602 static gboolean save_yourself_cb(GnomeClient *client,
603  gint /* phase */,
604  GnomeSaveStyle /* style */,
605  gboolean shutdown,
606  GnomeInteractStyle interact,
607  gboolean /* fast */,
608  gpointer /* user_data */)
609 {
610  if (!shutdown || interact != GNOME_INTERACT_ANY) {
611  return TRUE;
612  }
613 
614  if (AllProjects{}.empty()) {
615  return TRUE;
616  }
617 
618  gnome_client_request_interaction(client,
619  GNOME_DIALOG_NORMAL,
620  interact_cb,
621  NULL);
622 
623  return TRUE;
624 }
625 
626 class GnomeShutdown
627 {
628  public:
629  GnomeShutdown()
630  {
631  mArgv[0].reset(strdup("Audacity"));
632 
633  mGnomeui = dlopen("libgnomeui-2.so.0", RTLD_NOW);
634  if (!mGnomeui) {
635  return;
636  }
637 
638  mGnome = dlopen("libgnome-2.so.0", RTLD_NOW);
639  if (!mGnome) {
640  return;
641  }
642 
643  _gnome_program_init_fn gnome_program_init = (_gnome_program_init_fn)
644  dlsym(mGnome, "gnome_program_init");
645  _libgnomeui_module_info_get_fn libgnomeui_module_info_get = (_libgnomeui_module_info_get_fn)
646  dlsym(mGnomeui, "libgnomeui_module_info_get");
647  _gnome_master_client_fn gnome_master_client = (_gnome_master_client_fn)
648  dlsym(mGnomeui, "gnome_master_client");
649 
650  gnome_client_request_interaction = (_gnome_client_request_interaction_fn)
651  dlsym(mGnomeui, "gnome_client_request_interaction");
652  gnome_interaction_key_return = (_gnome_interaction_key_return_fn)
653  dlsym(mGnomeui, "gnome_interaction_key_return");
654 
655 
656  if (!gnome_program_init || !libgnomeui_module_info_get) {
657  return;
658  }
659 
660  gnome_program_init(mArgv[0].get(),
661  "1.0",
662  libgnomeui_module_info_get(),
663  1,
664  reinterpret_cast<char**>(mArgv),
665  NULL);
666 
667  mClient = gnome_master_client();
668  if (mClient == NULL) {
669  return;
670  }
671 
672  g_signal_connect(mClient, "save-yourself", G_CALLBACK(save_yourself_cb), NULL);
673  }
674 
675  virtual ~GnomeShutdown()
676  {
677  // Do not dlclose() the libraries here lest you want segfaults...
678  }
679 
680  private:
681 
682  MallocString<> mArgv[1];
683  void *mGnomeui;
684  void *mGnome;
685  GnomeClient *mClient;
686 };
687 
688 // This variable exists to call the constructor and
689 // connect a signal for the 'save-yourself' message.
690 GnomeShutdown GnomeShutdownInstance;
691 
692 #endif
693 
694 // Where drag/drop or "Open With" filenames get stored until
695 // the timer routine gets around to picking them up.
696 static wxArrayString ofqueue;
697 
698 //
699 // DDE support for opening multiple files with one instance
700 // of Audacity.
701 //
702 
703 #define IPC_APPL wxT("audacity")
704 #define IPC_TOPIC wxT("System")
705 
706 class IPCConn final : public wxConnection
707 {
708 public:
710  : wxConnection()
711  {
712  };
713 
715  {
716  };
717 
718  bool OnExec(const wxString & WXUNUSED(topic),
719  const wxString & data)
720  {
721  // Add the filename to the queue. It will be opened by
722  // the OnTimer() event when it is safe to do so.
723  ofqueue.push_back(data);
724 
725  return true;
726  }
727 };
728 
729 class IPCServ final : public wxServer
730 {
731 public:
732  IPCServ(const wxString & appl)
733  : wxServer()
734  {
735  Create(appl);
736  };
737 
739  {
740  };
741 
742  wxConnectionBase *OnAcceptConnection(const wxString & topic) override
743  {
744  if (topic != IPC_TOPIC) {
745  return NULL;
746  }
747 
748  // Trust wxWidgets framework to DELETE it
749  return safenew IPCConn();
750  };
751 };
752 
753 #if defined(__WXMAC__)
754 
755 IMPLEMENT_APP_NO_MAIN(AudacityApp)
756 IMPLEMENT_WX_THEME_SUPPORT
757 
758 int main(int argc, char *argv[])
759 {
760  wxDISABLE_DEBUG_SUPPORT();
761 
762  return wxEntry(argc, argv);
763 }
764 
765 #elif defined(__WXGTK__) && defined(NDEBUG)
766 
767 IMPLEMENT_APP_NO_MAIN(AudacityApp)
768 IMPLEMENT_WX_THEME_SUPPORT
769 
770 int main(int argc, char *argv[])
771 {
772  wxDISABLE_DEBUG_SUPPORT();
773 
774  // Bug #1986 workaround - This doesn't actually reduce the number of
775  // messages, it simply hides them in Release builds. We'll probably
776  // never be able to get rid of the messages entirely, but we should
777  // look into what's causing them, so allow them to show in Debug
778  // builds.
779  stdout = freopen("/dev/null", "w", stdout);
780  stderr = freopen("/dev/null", "w", stderr);
781 
782  return wxEntry(argc, argv);
783 }
784 
785 #else
786 IMPLEMENT_APP(AudacityApp)
787 #endif
788 
789 #ifdef __WXMAC__
790 
791 // in response of an open-document apple event
792 void AudacityApp::MacOpenFile(const wxString &fileName)
793 {
794  ofqueue.push_back(fileName);
795 }
796 
797 // in response of a print-document apple event
798 void AudacityApp::MacPrintFile(const wxString &fileName)
799 {
800  ofqueue.push_back(fileName);
801 }
802 
803 // in response of a open-application apple event
804 void AudacityApp::MacNewFile()
805 {
806  if (!gInited)
807  return;
808 
809  // This method should only be used on the Mac platform
810  // when no project windows are open.
811 
812  if (AllProjects{}.empty())
813  (void) ProjectManager::New();
814 }
815 
816 #endif //__WXMAC__
817 
818 // IPC communication
819 #define ID_IPC_SERVER 6200
820 #define ID_IPC_SOCKET 6201
821 
822 // we don't really care about the timer id, but set this value just in case we do in the future
823 #define kAudacityAppTimerID 0
824 
825 BEGIN_EVENT_TABLE(AudacityApp, wxApp)
826  EVT_IDLE( AudacityApp::OnIdle )
827 
828  EVT_QUERY_END_SESSION(AudacityApp::OnQueryEndSession)
829  EVT_END_SESSION(AudacityApp::OnEndSession)
830 
832 #ifdef __WXMAC__
836  EVT_MENU(wxID_PREFERENCES, AudacityApp::OnMenuPreferences)
837 #endif
838 
839  // Associate the handler with the menu id on all operating systems, even
840  // if they don't have an application menu bar like in macOS, so that
841  // other parts of the program can send the application a shut-down
842  // event
844 
845 #ifndef __WXMSW__
848 #endif
849 
850  // Recent file event handlers.
852  EVT_MENU_RANGE(FileHistory::ID_RECENT_FIRST, FileHistory::ID_RECENT_LAST,
853  AudacityApp::OnMRUFile)
854 
855  // Handle AppCommandEvents (usually from a script)
856  EVT_APP_COMMAND(wxID_ANY, AudacityApp::OnReceiveCommand)
857 
858  // Global ESC key handling
859  EVT_KEY_DOWN(AudacityApp::OnKeyDown)
861 
862 // backend for OnMRUFile
863 // TODO: Would be nice to make this handle not opening a file with more panache.
864 // - Inform the user if DefaultOpenPath not set.
865 // - Switch focus to correct instance of project window, if already open.
866 bool AudacityApp::MRUOpen(const FilePath &fullPathStr) {
867  // Most of the checks below are copied from ProjectManager::OpenFiles.
868  // - some rationalisation might be possible.
869 
870  auto pProj = GetActiveProject().lock();
871  auto proj = pProj.get();
872 
873  if (!fullPathStr.empty())
874  {
875  // verify that the file exists
876  if (wxFile::Exists(fullPathStr))
877  {
878  FileNames::UpdateDefaultPath(FileNames::Operation::Open, ::wxPathOnly(fullPathStr));
879 
880  // Make sure it isn't already open.
881  // Test here even though AudacityProject::OpenFile() also now checks, because
882  // that method does not return the bad result.
883  // That itself may be a FIXME.
884  if (ProjectFileManager::IsAlreadyOpen(fullPathStr))
885  return false;
886 
888  ( void ) ProjectManager::OpenProject( proj, fullPathStr,
889  true /* addtohistory */, false /* reuseNonemptyProject */ );
890  }
891  else {
892  // File doesn't exist - remove file from history
894  XO(
895 "%s could not be found.\n\nIt has been removed from the list of recent files.")
896  .Format(fullPathStr) );
897  return(false);
898  }
899  }
900  return(true);
901 }
902 
903 bool AudacityApp::SafeMRUOpen(const wxString &fullPathStr)
904 {
905  return GuardedCall< bool >( [&]{ return MRUOpen( fullPathStr ); } );
906 }
907 
908 void AudacityApp::OnMRUClear(wxCommandEvent& WXUNUSED(event))
909 {
911 }
912 
913 //vvv Basically, anything from Recent Files is treated as a .aup3, until proven otherwise,
914 // then it tries to Import(). Very questionable handling, imo.
915 // Better, for example, to check the file type early on.
916 void AudacityApp::OnMRUFile(wxCommandEvent& event) {
917  int n = event.GetId() - FileHistory::ID_RECENT_FIRST;
918  auto &history = FileHistory::Global();
919  const auto &fullPathStr = history[ n ];
920 
921  // Try to open only if not already open.
922  // Test IsAlreadyOpen() here even though AudacityProject::MRUOpen() also now checks,
923  // because we don't want to Remove() just because it already exists,
924  // and AudacityApp::OnMacOpenFile() calls MRUOpen() directly.
925  // that method does not return the bad result.
926  // PRL: Don't call SafeMRUOpen
927  // -- if open fails for some exceptional reason of resource exhaustion that
928  // the user can correct, leave the file in history.
929  if (!ProjectFileManager::IsAlreadyOpen(fullPathStr) && !MRUOpen(fullPathStr))
930  history.Remove(n);
931 }
932 
933 void AudacityApp::OnTimer(wxTimerEvent& WXUNUSED(event))
934 {
935  // Filenames are queued when Audacity receives a few of the
936  // AppleEvent messages (via wxWidgets). So, open any that are
937  // in the queue and clean the queue.
938  if (gInited) {
939  if (ofqueue.size()) {
940  // Load each file on the queue
941  while (ofqueue.size()) {
942  wxString name;
943  name.swap(ofqueue[0]);
944  ofqueue.erase( ofqueue.begin() );
945 
946  // Get the user's attention if no file name was specified
947  if (name.empty()) {
948  // Get the users attention
949  if (auto project = GetActiveProject().lock()) {
950  auto &window = GetProjectFrame( *project );
951  window.Maximize();
952  window.Raise();
953  window.RequestUserAttention();
954  }
955  continue;
956  }
957 
958  // TODO: Handle failures better.
959  // Some failures are OK, e.g. file not found, just would-be-nices to do better,
960  // so FAIL_MSG is more a case of an enhancement request than an actual problem.
961  // LL: In all but one case an appropriate message is already displayed. The
962  // instance that a message is NOT displayed is when a failure to write
963  // to the config file has occurred.
964  // PRL: Catch any exceptions, don't try this file again, continue to
965  // other files.
966  if (!SafeMRUOpen(name)) {
967  // Just log it. Assertion failure is not appropriate on valid
968  // defensive path against bad file data.
969  wxLogMessage(wxT("MRUOpen failed"));
970  }
971  }
972  }
973  }
974 }
975 
976 #if defined(__WXMSW__)
977 #define WL(lang, sublang) (lang), (sublang),
978 #else
979 #define WL(lang,sublang)
980 #endif
981 
982 #if wxCHECK_VERSION(3, 0, 1)
983 wxLanguageInfo userLangs[] =
984 {
985  // Bosnian is defined in wxWidgets already
986 // { wxLANGUAGE_USER_DEFINED, wxT("bs"), WL(0, SUBLANG_DEFAULT) wxT("Bosnian"), wxLayout_LeftToRight },
987 
988  { wxLANGUAGE_USER_DEFINED, wxT("eu"), WL(0, SUBLANG_DEFAULT) wxT("Basque"), wxLayout_LeftToRight },
989 };
990 #endif
991 
993 {
994 #if defined(HAS_CRASH_REPORT)
995  CrashReport::Generate(wxDebugReport::Context_Exception);
996 #endif
997 
998  exit(-1);
999 }
1000 
1001 
1002 #ifdef _MSC_VER
1003 // If this is compiled with MSVC (Visual Studio)
1004 #pragma warning( push )
1005 #pragma warning( disable : 4702) // unreachable code warning.
1006 #endif //_MSC_VER
1007 
1009 {
1010  // This function is invoked from catch blocks in the wxWidgets framework,
1011  // and throw; without argument re-throws the exception being handled,
1012  // letting us dispatch according to its type.
1013 
1014  try { throw; }
1015  catch ( AudacityException &e ) {
1016  (void)e;// Compiler food
1017  // Here is the catch-all for our own exceptions
1018 
1019  // Use CallAfter to delay this to the next pass of the event loop,
1020  // rather than risk doing it inside stack unwinding.
1021  auto pProject = ::GetActiveProject().lock();
1022  auto pException = std::current_exception();
1023  CallAfter( [pException, pProject] {
1024 
1025  // Restore the state of the project to what it was before the
1026  // failed operation
1027  if (pProject) {
1028  ProjectHistory::Get( *pProject ).RollbackState();
1029 
1030  // Forget pending changes in the TrackList
1031  TrackList::Get( *pProject ).ClearPendingTracks();
1032 
1033  ProjectWindow::Get( *pProject ).RedrawProject();
1034  }
1035 
1036  // Give the user an alert
1037  try { std::rethrow_exception( pException ); }
1038  catch( AudacityException &e )
1039  { e.DelayedHandlerAction(); }
1040 
1041  } );
1042 
1043  // Don't quit the program
1044  return true;
1045  }
1046  catch ( ... ) {
1047  // There was some other type of exception we don't know.
1048  // Let the inherited function do throw; again and whatever else it does.
1049  return wxApp::OnExceptionInMainLoop();
1050  }
1051  // Shouldn't ever reach this line
1052  return false;
1053 }
1054 #ifdef _MSC_VER
1055 #pragma warning( pop )
1056 #endif //_MSC_VER
1057 
1059 {
1060 #if defined(USE_BREAKPAD)
1061  InitBreakpad();
1062 // Do not capture crashes in debug builds
1063 #elif !defined(_DEBUG)
1064 #if defined(HAS_CRASH_REPORT)
1065 #if defined(wxUSE_ON_FATAL_EXCEPTION) && wxUSE_ON_FATAL_EXCEPTION
1066  wxHandleFatalExceptions();
1067 #endif
1068 #endif
1069 #endif
1070 }
1071 
1073 {
1074 }
1075 
1076 // The `main program' equivalent, creating the windows and returning the
1077 // main frame
1079 {
1080  // JKC: ANSWER-ME: Who actually added the event loop guarantor?
1081  // Although 'blame' says Leland, I think it came from a donated patch.
1082 
1083  // PRL: It was added by LL at 54676a72285ba7ee3a69920e91fa390a71ef10c9 :
1084  // " Ensure OnInit() has an event loop
1085  // And allow events to flow so the splash window updates under GTK"
1086  // then mistakenly lost in the merge at
1087  // 37168ebbf67ae869ab71a3b5cbbf1d2a48e824aa
1088  // then restored at 7687972aa4b2199f0717165235f3ef68ade71e08
1089 
1090  // Ensure we have an event loop during initialization
1091  wxEventLoopGuarantor eventLoop;
1092 
1093  // Inject basic GUI services behind the facade
1094  {
1095  static wxWidgetsBasicUI uiServices;
1096  (void)BasicUI::Install(&uiServices);
1097  }
1098 
1099  // Fire up SQLite
1101  this->CallAfter([]{
1103  XO("SQLite library failed to initialize. Audacity cannot continue.") );
1104  QuitAudacity( true );
1105  });
1106 
1107 
1108  // cause initialization of wxWidgets' global logger target
1109  (void) AudacityLogger::Get();
1110 
1111 #if defined(__WXMAC__)
1112  // Disable window animation
1113  wxSystemOptions::SetOption(wxMAC_WINDOW_PLAIN_TRANSITION, 1);
1114 #endif
1115 
1116  // Some GTK themes produce larger combo boxes that make them taller
1117  // than our single toolbar height restriction. This will remove some
1118  // of the extra space themes add.
1119 #if defined(__WXGTK3__) && defined(HAVE_GTK)
1120  GtkWidget *combo = gtk_combo_box_new();
1121  GtkCssProvider *provider = gtk_css_provider_new();
1122  gtk_css_provider_load_from_data(GTK_CSS_PROVIDER(provider),
1123  ".linked entry,\n"
1124  ".linked button,\n"
1125  ".linked combobox box.linked button,\n"
1126  ".horizontal.linked entry,\n"
1127  ".horizontal.linked button,\n"
1128  ".horizontal.linked combobox box.linked button,\n"
1129  "combobox {\n"
1130  " padding-top: 0px;\n"
1131  " padding-bottom: 0px;\n"
1132  " padding-left: 4px;\n"
1133  " padding-right: 4px;\n"
1134  " margin: 0px;\n"
1135  " font-size: 95%;\n"
1136  "}", -1, NULL);
1137  gtk_style_context_add_provider_for_screen(gtk_widget_get_screen(combo),
1138  GTK_STYLE_PROVIDER (provider),
1139  GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
1140  g_object_unref(provider);
1141  g_object_unref(combo);
1142 #elif defined(__WXGTK__) && defined(HAVE_GTK)
1143  gtk_rc_parse_string("style \"audacity\" {\n"
1144  " GtkButton::inner_border = { 0, 0, 0, 0 }\n"
1145  " GtkEntry::inner_border = { 0, 0, 0, 0 }\n"
1146  " xthickness = 4\n"
1147  " ythickness = 0\n"
1148  "}\n"
1149  "widget_class \"*GtkCombo*\" style \"audacity\"");
1150 #endif
1151 
1152  wxTheApp->SetAppName(AppName);
1153  // Explicitly set since OSX will use it for the "Quit" menu item
1154  wxTheApp->SetAppDisplayName(AppName);
1155  wxTheApp->SetVendorName(AppName);
1156 
1157  ::wxInitAllImageHandlers();
1158 
1159  // AddHandler takes ownership
1160  wxFileSystem::AddHandler(safenew wxZipFSHandler);
1161 
1162  //
1163  // Paths: set search path and temp dir path
1164  //
1165  FilePaths audacityPathList;
1166 
1167 #ifdef __WXGTK__
1168  wxStandardPaths standardPaths = wxStandardPaths::Get();
1169  wxString portablePrefix = wxPathOnly(wxPathOnly(standardPaths.GetExecutablePath()));
1170 
1171  // Make sure install prefix is set so wxStandardPath resolves paths properly
1172  if (wxDirExists(portablePrefix + L"/share/audacity")) {
1173  // use prefix relative to executable location to make Audacity portable
1174  standardPaths.SetInstallPrefix(portablePrefix);
1175  } else {
1176  // fallback to hard-coded prefix set during configuration
1177  standardPaths.SetInstallPrefix(wxT(INSTALL_PREFIX));
1178  }
1179  wxString installPrefix = standardPaths.GetInstallPrefix();
1180 
1181  /* Search path (for plug-ins, translations etc) is (in this order):
1182  * The AUDACITY_PATH environment variable
1183  * The current directory
1184  * The user's "~/.audacity-data" or "Portable Settings" directory
1185  * The user's "~/.audacity-files" directory
1186  * The "share" and "share/doc" directories in their install path */
1187  wxString home = wxGetHomeDir();
1188 
1189  wxString envTempDir = wxGetenv(wxT("TMPDIR"));
1190  if (!envTempDir.empty()) {
1191  /* On Unix systems, the environment variable TMPDIR may point to
1192  an unusual path when /tmp and /var/tmp are not desirable. */
1193  TempDirectory::SetDefaultTempDir( wxString::Format(
1194  wxT("%s/audacity-%s"), envTempDir, wxGetUserId() ) );
1195  } else {
1196  /* On Unix systems, the default temp dir is in /var/tmp. */
1197  TempDirectory::SetDefaultTempDir( wxString::Format(
1198  wxT("/var/tmp/audacity-%s"), wxGetUserId() ) );
1199  }
1200 
1201 // DA: Path env variable.
1202 #ifndef EXPERIMENTAL_DA
1203  wxString pathVar = wxGetenv(wxT("AUDACITY_PATH"));
1204 #else
1205  wxString pathVar = wxGetenv(wxT("DARKAUDACITY_PATH"));
1206 #endif
1207  if (!pathVar.empty())
1208  FileNames::AddMultiPathsToPathList(pathVar, audacityPathList);
1209  FileNames::AddUniquePathToPathList(::wxGetCwd(), audacityPathList);
1210 
1211  wxString progPath = wxPathOnly(argv[0]);
1212  FileNames::AddUniquePathToPathList(progPath, audacityPathList);
1213  // Add the path to modules:
1214  FileNames::AddUniquePathToPathList(progPath + L"/lib/audacity", audacityPathList);
1215 
1217 
1218 #ifdef AUDACITY_NAME
1219  FileNames::AddUniquePathToPathList(wxString::Format(wxT("%s/.%s-files"),
1220  home, wxT(AUDACITY_NAME)),
1221  audacityPathList);
1223  audacityPathList);
1224  FileNames::AddUniquePathToPathList(wxString::Format(installPrefix + L"/share/%s", wxT(AUDACITY_NAME)),
1225  audacityPathList);
1226  FileNames::AddUniquePathToPathList(wxString::Format(installPrefix + L"/share/doc/%s", wxT(AUDACITY_NAME)),
1227  audacityPathList);
1228 #else //AUDACITY_NAME
1229  FileNames::AddUniquePathToPathList(wxString::Format(wxT("%s/.audacity-files"),
1230  home),
1231  audacityPathList)
1233  audacityPathList);
1234  FileNames::AddUniquePathToPathList(installPrefix + L"/share/audacity"),
1235  audacityPathList);
1236  FileNames::AddUniquePathToPathList(installPrefix + L"/share/doc/audacity",
1237  audacityPathList);
1238 #endif //AUDACITY_NAME
1239 
1240  FileNames::AddUniquePathToPathList(installPrefix + L"/share/locale",
1241  audacityPathList);
1242 
1243  FileNames::AddUniquePathToPathList(wxString::Format(wxT("./locale")),
1244  audacityPathList);
1245 
1246 #endif //__WXGTK__
1247 
1248 // JKC Bug 1220: Use path based on home directory on WXMAC
1249 #ifdef __WXMAC__
1250  wxFileName tmpFile;
1251  tmpFile.AssignHomeDir();
1252  wxString tmpDirLoc = tmpFile.GetPath(wxPATH_GET_VOLUME);
1253 #else
1254  wxFileName tmpFile;
1255  tmpFile.AssignTempFileName(wxT("nn"));
1256  wxString tmpDirLoc = tmpFile.GetPath(wxPATH_GET_VOLUME);
1257  ::wxRemoveFile(tmpFile.GetFullPath());
1258 #endif
1259 
1260 
1261 
1262  // On Mac and Windows systems, use the directory which contains Audacity.
1263 #ifdef __WXMSW__
1264  // On Windows, the path to the Audacity program is in argv[0]
1265  wxString progPath = wxPathOnly(argv[0]);
1266  FileNames::AddUniquePathToPathList(progPath, audacityPathList);
1267  FileNames::AddUniquePathToPathList(progPath + wxT("\\Languages"), audacityPathList);
1268 
1269  // See bug #1271 for explanation of location
1270  tmpDirLoc = FileNames::MkDir(wxStandardPaths::Get().GetUserLocalDataDir());
1271  TempDirectory::SetDefaultTempDir( wxString::Format(
1272  wxT("%s\\SessionData"), tmpDirLoc ) );
1273 #endif //__WXWSW__
1274 
1275 #ifdef __WXMAC__
1276  // On Mac OS X, the path to the Audacity program is in argv[0]
1277  wxString progPath = wxPathOnly(argv[0]);
1278 
1279  FileNames::AddUniquePathToPathList(progPath, audacityPathList);
1280  // If Audacity is a "bundle" package, then the root directory is
1281  // the great-great-grandparent of the directory containing the executable.
1282  //FileNames::AddUniquePathToPathList(progPath + wxT("/../../../"), audacityPathList);
1283 
1284  // These allow for searching the "bundle"
1286  progPath + wxT("/../"), audacityPathList);
1288  progPath + wxT("/../Resources"), audacityPathList);
1289 
1290  // JKC Bug 1220: Using an actual temp directory for session data on Mac was
1291  // wrong because it would get cleared out on a reboot.
1292  TempDirectory::SetDefaultTempDir( wxString::Format(
1293  wxT("%s/Library/Application Support/audacity/SessionData"), tmpDirLoc) );
1294 
1295  //TempDirectory::SetDefaultTempDir( wxString::Format(
1296  // wxT("%s/audacity-%s"),
1297  // tmpDirLoc,
1298  // wxGetUserId() ) );
1299 #endif //__WXMAC__
1300 
1301  FileNames::SetAudacityPathList( std::move( audacityPathList ) );
1302 
1303  // Define languages for which we have translations, but that are not yet
1304  // supported by wxWidgets.
1305  //
1306  // TODO: The whole Language initialization really need to be reworked.
1307  // It's all over the place.
1308 #if wxCHECK_VERSION(3, 0, 1)
1309  for (size_t i = 0, cnt = WXSIZEOF(userLangs); i < cnt; i++)
1310  {
1311  wxLocale::AddLanguage(userLangs[i]);
1312  }
1313 #endif
1314 
1315  // Initialize preferences and language
1316  {
1317  wxFileName configFileName(FileNames::DataDir(), wxT("audacity.cfg"));
1318  auto appName = wxTheApp->GetAppName();
1320  appName, wxEmptyString,
1321  configFileName.GetFullPath(),
1322  wxEmptyString, wxCONFIG_USE_LOCAL_FILE) );
1324  }
1325 
1326 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
1327  this->AssociateFileTypes();
1328 #endif
1329 
1331  SetPreferredSystemAppearance(appearance);
1332  });
1333 
1334  {
1335  wxBusyCursor busy;
1337  }
1338 
1339  // AColor depends on theTheme.
1340  AColor::Init();
1341 
1342  // If this fails, we must exit the program.
1343  if (!InitTempDir()) {
1345  return false;
1346  }
1347 
1348 #ifdef __WXMAC__
1349  // Bug2437: When files are opened from Finder and another instance of
1350  // Audacity is running, we must return from OnInit() to wxWidgets before
1351  // MacOpenFile is called, informing us of the paths that need to be
1352  // opened. So use CallAfter() to delay the rest of initialization.
1353  // See CreateSingleInstanceChecker() where we send those paths over a
1354  // socket to the prior instance.
1355 
1356  // This call is what probably makes the sleep unnecessary:
1357  MacFinishLaunching();
1358 
1359  using namespace std::chrono;
1360  // This sleep may be unnecessary, but it is harmless. It less NS framework
1361  // events arrive on another thread, but it might not always be long enough.
1362  std::this_thread::sleep_for(100ms);
1363  CallAfter([this]{
1364  if (!InitPart2())
1365  exit(-1);
1366  });
1367  return true;
1368 #else
1369  return InitPart2();
1370 #endif
1371 }
1372 
1374 {
1375 #if defined(__WXMAC__)
1376  SetExitOnFrameDelete(false);
1377 #endif
1378 
1379  // Make sure the temp dir isn't locked by another process.
1380  {
1381  auto key =
1382  PreferenceKey(FileNames::Operation::Temp, FileNames::PathType::_None);
1383  auto temp = gPrefs->Read(key);
1384  if (temp.empty() || !CreateSingleInstanceChecker(temp)) {
1386  return false;
1387  }
1388  }
1389 
1390  //<<<< Try to avoid dialogs before this point.
1391  // The reason is that InitTempDir starts the single instance checker.
1392  // If we're waiitng in a dialog before then we can very easily
1393  // start multiple instances, defeating the single instance checker.
1394 
1395  // Initialize the CommandHandler
1397 
1398  // Initialize the ModuleManager, including loading found modules
1400 
1401  // Initialize the PluginManager
1403 
1404  // Parse command line and handle options that might require
1405  // immediate exit...no need to initialize all of the audio
1406  // stuff to display the version string.
1407  std::shared_ptr< wxCmdLineParser > parser{ ParseCommandLine() };
1408  if (!parser)
1409  {
1410  // Either user requested help or a parsing error occurred
1411  exit(1);
1412  }
1413 
1414  if (parser->Found(wxT("v")))
1415  {
1416  wxPrintf("Audacity v%s\n", AUDACITY_VERSION_STRING);
1417  exit(0);
1418  }
1419 
1420  long lval;
1421  if (parser->Found(wxT("b"), &lval))
1422  {
1423  if (lval < 256 || lval > 100000000)
1424  {
1425  wxPrintf(_("Block size must be within 256 to 100000000\n"));
1426  exit(1);
1427  }
1428 
1430  }
1431 
1432  wxString fileName;
1433  if (parser->Found(wxT("j"), &fileName))
1434  Journal::SetInputFileName( fileName );
1435 
1436  // BG: Create a temporary window to set as the top window
1437  wxImage logoimage((const char **)AudacityLogoWithName_xpm);
1438  logoimage.Rescale(logoimage.GetWidth() / 2, logoimage.GetHeight() / 2);
1439  if( GetLayoutDirection() == wxLayout_RightToLeft)
1440  logoimage = logoimage.Mirror();
1441  wxBitmap logo(logoimage);
1442 
1443  AudacityProject *project;
1444  {
1445  // Bug 718: Position splash screen on same screen
1446  // as where Audacity project will appear.
1447  wxRect wndRect;
1448  bool bMaximized = false;
1449  bool bIconized = false;
1450  GetNextWindowPlacement(&wndRect, &bMaximized, &bIconized);
1451 
1452  wxSplashScreen temporarywindow(
1453  logo,
1454  wxSPLASH_CENTRE_ON_SCREEN | wxSPLASH_NO_TIMEOUT,
1455  0,
1456  NULL,
1457  wxID_ANY,
1458  wndRect.GetTopLeft(),
1459  wxDefaultSize,
1460  wxSTAY_ON_TOP);
1461 
1462  // Unfortunately with the Windows 10 Creators update, the splash screen
1463  // now appears before setting its position.
1464  // On a dual monitor screen it will appear on one screen and then
1465  // possibly jump to the second.
1466  // We could fix this by writing our own splash screen and using Hide()
1467  // until the splash scren was correctly positioned, then Show()
1468 
1469  // Possibly move it on to the second screen...
1470  temporarywindow.SetPosition( wndRect.GetTopLeft() );
1471  // Centered on whichever screen it is on.
1472  temporarywindow.Center();
1473  temporarywindow.SetTitle(_("Audacity is starting up..."));
1474  SetTopWindow(&temporarywindow);
1475  temporarywindow.Raise();
1476 
1477  // ANSWER-ME: Why is YieldFor needed at all?
1478  //wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI|wxEVT_CATEGORY_USER_INPUT|wxEVT_CATEGORY_UNKNOWN);
1479  wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI);
1480 
1481  //JKC: Would like to put module loading here.
1482 
1483  // More initialization
1484 
1485  InitDitherers();
1486  AudioIO::Init();
1487 
1488 #ifdef __WXMAC__
1489 
1490  // On the Mac, users don't expect a program to quit when you close the last window.
1491  // Create a menubar that will show when all project windows are closed.
1492 
1493  auto fileMenu = std::make_unique<wxMenu>();
1494  auto urecentMenu = std::make_unique<wxMenu>();
1495  auto recentMenu = urecentMenu.get();
1496  fileMenu->Append(wxID_NEW, wxString(_("&New")) + wxT("\tCtrl+N"));
1497  fileMenu->Append(wxID_OPEN, wxString(_("&Open...")) + wxT("\tCtrl+O"));
1498  fileMenu->AppendSubMenu(urecentMenu.release(), _("Open &Recent..."));
1499  fileMenu->Append(wxID_ABOUT, _("&About Audacity..."));
1500  fileMenu->Append(wxID_PREFERENCES, wxString(_("&Preferences...")) + wxT("\tCtrl+,"));
1501 
1502  {
1503  auto menuBar = std::make_unique<wxMenuBar>();
1504  menuBar->Append(fileMenu.release(), _("&File"));
1505 
1506  // PRL: Are we sure wxWindows will not leak this menuBar?
1507  // The online documentation is not explicit.
1508  wxMenuBar::MacSetCommonMenuBar(menuBar.release());
1509  }
1510 
1511  auto &recentFiles = FileHistory::Global();
1512  recentFiles.UseMenu(recentMenu);
1513 
1514 #endif //__WXMAC__
1515  temporarywindow.Show(false);
1516  }
1517 
1518  // Must do this before creating the first project, else the early exit path
1519  // may crash
1520  if ( !Journal::Begin( FileNames::DataDir() ) )
1521  return false;
1522 
1523  // Workaround Bug 1377 - Crash after Audacity starts and low disk space warning appears
1524  // The temporary splash window is closed AND cleaned up, before attempting to create
1525  // a project and possibly creating a modal warning dialog by doing so.
1526  // Also fixes problem of warning being obscured.
1527  // Downside is that we have no splash screen for the (brief) time that we spend
1528  // creating the project.
1529  // Root cause is problem with wxSplashScreen and other dialogs co-existing, that
1530  // seemed to arrive with wx3.
1531  {
1532  project = ProjectManager::New();
1533  }
1534 
1535  if( ProjectSettings::Get( *project ).GetShowSplashScreen() ){
1536  // This may do a check-for-updates at every start up.
1537  // Mainly this is to tell users of ALPHAS who don't know that they have an ALPHA.
1538  // Disabled for now, after discussion.
1539  // project->MayCheckForUpdates();
1540  SplashDialog::DoHelpWelcome(*project);
1541  }
1542 
1543 #if defined(HAVE_UPDATES_CHECK)
1545 #endif
1546 
1547  #ifdef USE_FFMPEG
1548  FFmpegStartup();
1549  #endif
1550 
1552 
1553  // Bug1561: delay the recovery dialog, to avoid crashes.
1554  CallAfter( [=] () mutable {
1555  // Remove duplicate shortcuts when there's a change of version
1556  int vMajorInit, vMinorInit, vMicroInit;
1557  gPrefs->GetVersionKeysInit(vMajorInit, vMinorInit, vMicroInit);
1558  if (vMajorInit != AUDACITY_VERSION || vMinorInit != AUDACITY_RELEASE
1559  || vMicroInit != AUDACITY_REVISION) {
1561  }
1562  //
1563  // Auto-recovery
1564  //
1565  bool didRecoverAnything = false;
1566  // This call may reassign project (passed by reference)
1567  if (!ShowAutoRecoveryDialogIfNeeded(project, &didRecoverAnything))
1568  {
1569  QuitAudacity(true);
1570  }
1571 
1572  //
1573  // Remainder of command line parsing, but only if we didn't recover
1574  //
1575  if (project && !didRecoverAnything)
1576  {
1577  if (parser->Found(wxT("t")))
1578  {
1579  RunBenchmark( nullptr, *project);
1580  QuitAudacity(true);
1581  }
1582 
1583  for (size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
1584  {
1585  // PRL: Catch any exceptions, don't try this file again, continue to
1586  // other files.
1587  SafeMRUOpen(parser->GetParam(i));
1588  }
1589  }
1590  } );
1591 
1592  gInited = true;
1593 
1595 
1596  mTimer.SetOwner(this, kAudacityAppTimerID);
1597  mTimer.Start(200);
1598 
1599 #ifdef EXPERIMENTAL_EASY_CHANGE_KEY_BINDINGS
1600  CommandManager::SetMenuHook( [](const CommandID &id){
1601  if (::wxGetMouseState().ShiftDown()) {
1602  // Only want one page of the preferences
1603  PrefsPanel::Factories factories;
1604  factories.push_back(KeyConfigPrefsFactory( id ));
1605  const auto pProject = GetActiveProject().lock();
1606  auto pWindow = FindProjectFrame( pProject.get() );
1607  // pProject may be null
1608  GlobalPrefsDialog dialog( pWindow, pProject.get(), factories );
1609  dialog.ShowModal();
1611  return true;
1612  }
1613  else
1614  return false;
1615  } );
1616 #endif
1617 
1618 #if defined(__WXMAC__)
1619  // The first time this version of Audacity is run or when the preferences
1620  // are reset, execute the "tccutil" command to reset the microphone permissions
1621  // currently assigned to Audacity. The end result is that the user will be
1622  // prompted to approve/deny Audacity access (again).
1623  //
1624  // This should resolve confusion of why Audacity appears to record, but only
1625  // gets silence due to Audacity being denied microphone access previously.
1626  bool permsReset = false;
1627  gPrefs->Read(wxT("/MicrophonePermissionsReset"), &permsReset, false);
1628  if (!permsReset) {
1629  system("tccutil reset Microphone org.audacityteam.audacity");
1630  gPrefs->Write(wxT("/MicrophonePermissionsReset"), true);
1631  }
1632 #endif
1633 
1634 #if defined(__WXMAC__)
1635  // Bug 2709: Workaround CoreSVG locale issue
1636  Bind(wxEVT_MENU_OPEN, [=](wxMenuEvent &event)
1637  {
1638  wxSetlocale(LC_NUMERIC, wxString(wxT("C")));
1639  event.Skip();
1640  });
1641 
1642  Bind(wxEVT_MENU_CLOSE, [=](wxMenuEvent &event)
1643  {
1644  wxSetlocale(LC_NUMERIC, Languages::GetLocaleName());
1645  event.Skip();
1646  });
1647 #endif
1648 
1649  return TRUE;
1650 }
1651 
1653 {
1654  // Returns 0 to the command line if the run completed normally
1655  auto result = wxApp::OnRun();
1656  if (result == 0)
1657  // If not otherwise abnormal, report any journal sync failure
1658  result = Journal::GetExitCode();
1659  return result;
1660 }
1661 
1662 void AudacityApp::OnIdle( wxIdleEvent &evt )
1663 {
1664  evt.Skip();
1665  try {
1666  if ( Journal::Dispatch() )
1667  evt.RequestMore();
1668  }
1669  catch( ... ) {
1670  // Hmm, wxWidgets doesn't guard calls to the idle handler as for other
1671  // events. So replicate some of the try-catch logic here.
1673  // Fall through and return, allowing delayed handler action of
1674  // AudacityException to clean up
1675  }
1676 }
1677 
1679 {
1680  mCmdHandler = std::make_unique<CommandHandler>();
1681  //SetNextHandler(mCmdHandler);
1682 }
1683 
1684 // AppCommandEvent callback - just pass the event on to the CommandHandler
1686 {
1687  wxASSERT(NULL != mCmdHandler);
1688  mCmdHandler->OnReceiveCommand(event);
1689 }
1690 
1691 void AudacityApp::OnKeyDown(wxKeyEvent &event)
1692 {
1693  if(event.GetKeyCode() == WXK_ESCAPE) {
1694  // Stop play, including scrub, but not record
1695  if ( auto project = ::GetActiveProject().lock() ) {
1696  auto token = ProjectAudioIO::Get( *project ).GetAudioIOToken();
1697  auto &scrubber = Scrubber::Get( *project );
1698  auto scrubbing = scrubber.HasMark();
1699  if (scrubbing)
1700  scrubber.Cancel();
1701  auto gAudioIO = AudioIO::Get();
1702  if((token > 0 &&
1703  gAudioIO->IsAudioTokenActive(token) &&
1704  gAudioIO->GetNumCaptureChannels() == 0) ||
1705  scrubbing)
1706  // ESC out of other play (but not record)
1707  ProjectAudioManager::Get( *project ).Stop();
1708  else
1709  event.Skip();
1710  }
1711  }
1712 
1713  event.Skip();
1714 }
1715 
1716 // Ensures directory is created and puts the name into result.
1717 // result is unchanged if unsuccessful.
1718 void SetToExtantDirectory( wxString & result, const wxString & dir ){
1719  // don't allow path of "".
1720  if( dir.empty() )
1721  return;
1722  if( wxDirExists( dir ) ){
1723  result = dir;
1724  return;
1725  }
1726  // Use '/' so that this works on Mac and Windows alike.
1727  wxFileName name( dir + "/junkname.cfg" );
1728  if( name.Mkdir( wxS_DIR_DEFAULT , wxPATH_MKDIR_FULL ) )
1729  result = dir;
1730 }
1731 
1733 {
1734  // We need to find a temp directory location.
1735  auto tempFromPrefs = TempDirectory::TempDir();
1736  auto tempDefaultLoc = TempDirectory::DefaultTempDir();
1737 
1738  wxString temp;
1739 
1740  #ifdef __WXGTK__
1741  if (tempFromPrefs.length() > 0 && tempFromPrefs[0] != wxT('/'))
1742  tempFromPrefs = wxT("");
1743  #endif
1744 
1745  // Stop wxWidgets from printing its own error messages
1746 
1747  wxLogNull logNo;
1748 
1749  // Try temp dir that was stored in prefs first
1750  if( TempDirectory::IsTempDirectoryNameOK( tempFromPrefs ) )
1751  SetToExtantDirectory( temp, tempFromPrefs );
1752 
1753  // If that didn't work, try the default location
1754 
1755  if (temp.empty())
1756  SetToExtantDirectory( temp, tempDefaultLoc );
1757 
1758  // Check temp directory ownership on *nix systems only
1759  #ifdef __UNIX__
1760  struct stat tempStatBuf;
1761  if ( lstat(temp.mb_str(), &tempStatBuf) != 0 ) {
1762  temp.clear();
1763  }
1764  else {
1765  if ( geteuid() != tempStatBuf.st_uid ) {
1766  temp.clear();
1767  }
1768  }
1769  #endif
1770 
1771  if (temp.empty()) {
1772  // Failed
1773  if( !TempDirectory::IsTempDirectoryNameOK( tempFromPrefs ) ) {
1775 "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."));
1776  } else {
1778 "Audacity could not find a place to store temporary files.\nPlease enter an appropriate directory in the preferences dialog."));
1779  }
1780 
1781  // Only want one page of the preferences
1782  PrefsPanel::Factories factories;
1783  factories.push_back(DirectoriesPrefsFactory());
1784  GlobalPrefsDialog dialog(nullptr, nullptr, factories);
1785  dialog.ShowModal();
1786 
1788 "Audacity is now going to exit. Please launch Audacity again to use the new temporary directory."));
1789  return false;
1790  }
1791 
1792  // The permissions don't always seem to be set on
1793  // some platforms. Hopefully this fixes it...
1794  #ifdef __UNIX__
1795  chmod(OSFILENAME(temp), 0700);
1796  #endif
1797 
1799  FileNames::UpdateDefaultPath(FileNames::Operation::Temp, temp);
1800 
1801  return true;
1802 }
1803 
1804 #if defined(__WXMSW__)
1805 
1806 // Return true if there are no other instances of Audacity running,
1807 // false otherwise.
1808 
1809 bool AudacityApp::CreateSingleInstanceChecker(const wxString &dir)
1810 {
1811  wxString name = wxString::Format(wxT("audacity-lock-%s"), wxGetUserId());
1812  mChecker.reset();
1813  auto checker = std::make_unique<wxSingleInstanceChecker>();
1814 
1815  auto runningTwoCopiesStr = XO("Running two copies of Audacity simultaneously may cause\ndata loss or cause your system to crash.\n\n");
1816 
1817  if (!checker->Create(name, dir))
1818  {
1819  // Error initializing the wxSingleInstanceChecker. We don't know
1820  // whether there is another instance running or not.
1821 
1822  auto prompt = XO(
1823 "Audacity was not able to lock the temporary files directory.\nThis folder may be in use by another copy of Audacity.\n")
1824  + runningTwoCopiesStr
1825  + XO("Do you still want to start Audacity?");
1826  int action = AudacityMessageBox(
1827  prompt,
1828  XO("Error Locking Temporary Folder"),
1829  wxYES_NO | wxICON_EXCLAMATION, NULL);
1830  if (action == wxNO)
1831  return false;
1832  }
1833  else if ( checker->IsAnotherRunning() ) {
1834  // Parse the command line to ensure correct syntax, but
1835  // ignore options other than -v, and only use the filenames, if any.
1836  auto parser = ParseCommandLine();
1837  if (!parser)
1838  {
1839  // Complaints have already been made
1840  return false;
1841  }
1842 
1843  if (parser->Found(wxT("v")))
1844  {
1845  wxPrintf("Audacity v%s\n", AUDACITY_VERSION_STRING);
1846  return false;
1847  }
1848 
1849  // Windows and Linux require absolute file names as command may
1850  // not come from current working directory.
1851  FilePaths filenames;
1852  for (size_t i = 0, cnt = parser->GetParamCount(); i < cnt; i++)
1853  {
1854  wxFileName filename(parser->GetParam(i));
1855  if (filename.MakeAbsolute())
1856  {
1857  filenames.push_back(filename.GetLongPath());
1858  }
1859  }
1860 
1861  // On Windows, we attempt to make a connection
1862  // to an already active Audacity. If successful, we send
1863  // the first command line argument (the audio file name)
1864  // to that Audacity for processing.
1865  wxClient client;
1866 
1867  // We try up to 50 times since there's a small window
1868  // where the server may not have been fully initialized.
1869  for (int i = 0; i < 50; i++)
1870  {
1871  std::unique_ptr<wxConnectionBase> conn{ client.MakeConnection(wxEmptyString, IPC_APPL, IPC_TOPIC) };
1872  if (conn)
1873  {
1874  bool ok = false;
1875  if (filenames.size() > 0)
1876  {
1877  for (size_t i = 0, cnt = filenames.size(); i < cnt; i++)
1878  {
1879  ok = conn->Execute(filenames[i]);
1880  }
1881  }
1882  else
1883  {
1884  // Send an empty string to force existing Audacity to front
1885  ok = conn->Execute(wxEmptyString);
1886  }
1887 
1888  if (ok)
1889  return false;
1890  }
1891 
1892  wxMilliSleep(10);
1893  }
1894  // There is another copy of Audacity running. Force quit.
1895 
1896  auto prompt = XO(
1897 "The system has detected that another copy of Audacity is running.\n")
1898  + runningTwoCopiesStr
1899  + XO(
1900 "Use the New or Open commands in the currently running Audacity\nprocess to open multiple projects simultaneously.\n");
1902  prompt, XO("Audacity is already running"),
1903  wxOK | wxICON_ERROR);
1904 
1905  return false;
1906  }
1907 
1908  // Create the DDE IPC server
1909  mIPCServ = std::make_unique<IPCServ>(IPC_APPL);
1910  mChecker = std::move(checker);
1911  return true;
1912 }
1913 #endif
1914 
1915 #if defined(__UNIX__)
1916 
1917 #include <sys/ipc.h>
1918 #include <sys/sem.h>
1919 #include <sys/shm.h>
1920 
1921 // Return true if there are no other instances of Audacity running,
1922 // false otherwise.
1923 
1924 bool AudacityApp::CreateSingleInstanceChecker(const wxString &dir)
1925 {
1926  mIPCServ.reset();
1927 
1928  bool isServer = false;
1929  wxIPV4address addr;
1930  addr.LocalHost();
1931 
1932  struct sembuf op = {};
1933 
1934  // Generate the IPC key we'll use for both shared memory and semaphores.
1935  wxString datadir = FileNames::DataDir();
1936  key_t memkey = ftok(datadir.c_str(), 0);
1937  key_t servkey = ftok(datadir.c_str(), 1);
1938  key_t lockkey = ftok(datadir.c_str(), 2);
1939 
1940  // Create and map the shared memory segment where the port number
1941  // will be stored.
1942  int memid = shmget(memkey, sizeof(int), IPC_CREAT | S_IRUSR | S_IWUSR);
1943  int *portnum = (int *) shmat(memid, nullptr, 0);
1944 
1945  // Create (or return) the SERVER semaphore ID
1946  int servid = semget(servkey, 1, IPC_CREAT | S_IRUSR | S_IWUSR);
1947 
1948  // Create the LOCK semaphore only if it doesn't already exist.
1949  int lockid = semget(lockkey, 1, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
1950 
1951  // If the LOCK semaphore was successfully created, then this is the first
1952  // time Audacity has been run during this boot of the system. In this
1953  // case we know we'll become the "server" application, so set up the
1954  // semaphores to prepare for it.
1955  if (lockid != -1)
1956  {
1957  // Initialize value of each semaphore, 1 indicates released and 0
1958  // indicates acquired.
1959  //
1960  // Note that this action is NOT recorded in the semaphore's
1961  // UNDO buffer.
1962  semctl(servid, 0, SETVAL, 1);
1963  semctl(lockid, 0, SETVAL, 1);
1964 
1965  // Now acquire them so the semaphores will be set to the
1966  // released state when the process terminates.
1967  op.sem_num = 0;
1968  op.sem_op = -1;
1969  op.sem_flg = SEM_UNDO;
1970  if (semop(lockid, &op, 1) == -1 || semop(servid, &op, 1) == -1)
1971  {
1973  XO("Unable to acquire semaphores.\n\n"
1974  "This is likely due to a resource shortage\n"
1975  "and a reboot may be required."),
1976  XO("Audacity Startup Failure"),
1977  wxOK | wxICON_ERROR);
1978 
1979  return false;
1980  }
1981 
1982  // We will be the server...
1983  isServer = true;
1984  }
1985  // Something catastrophic must have happened, so bail.
1986  else if (errno != EEXIST)
1987  {
1989  XO("Unable to create semaphores.\n\n"
1990  "This is likely due to a resource shortage\n"
1991  "and a reboot may be required."),
1992  XO("Audacity Startup Failure"),
1993  wxOK | wxICON_ERROR);
1994 
1995  return false;
1996  }
1997  // Otherwise it's a normal startup and we need to determine whether
1998  // we'll be the server or the client.
1999  else
2000  {
2001  // Retrieve the LOCK semaphore since we wouldn't have gotten it above.
2002  lockid = semget(lockkey, 1, 0);
2003 
2004  // Acquire the LOCK semaphore. We may block here if another
2005  // process is currently setting up the server.
2006  op.sem_num = 0;
2007  op.sem_op = -1;
2008  op.sem_flg = SEM_UNDO;
2009  if (semop(lockid, &op, 1) == -1)
2010  {
2012  XO("Unable to acquire lock semaphore.\n\n"
2013  "This is likely due to a resource shortage\n"
2014  "and a reboot may be required."),
2015  XO("Audacity Startup Failure"),
2016  wxOK | wxICON_ERROR);
2017 
2018  return false;
2019  }
2020 
2021  // Try to acquire the SERVER semaphore. If it's not currently active, then
2022  // we will become the server. Otherwise, this will fail and we'll know that
2023  // the server is already active and we will become the client.
2024  op.sem_num = 0;
2025  op.sem_op = -1;
2026  op.sem_flg = IPC_NOWAIT | SEM_UNDO;
2027  if (semop(servid, &op, 1) == 0)
2028  {
2029  isServer = true;
2030  }
2031  else if (errno != EAGAIN)
2032  {
2034  XO("Unable to acquire server semaphore.\n\n"
2035  "This is likely due to a resource shortage\n"
2036  "and a reboot may be required."),
2037  XO("Audacity Startup Failure"),
2038  wxOK | wxICON_ERROR);
2039 
2040  return false;
2041  }
2042  }
2043 
2044  // Initialize the socket server if we're to be the server.
2045  if (isServer)
2046  {
2047  // The system will randomly assign a port
2048  addr.Service(0);
2049 
2050  // Create the socket and bind to it.
2051  auto serv = std::make_unique<wxSocketServer>(addr, wxSOCKET_NOWAIT);
2052  if (serv && serv->IsOk())
2053  {
2054  serv->SetEventHandler(*this, ID_IPC_SERVER);
2055  serv->SetNotify(wxSOCKET_CONNECTION_FLAG);
2056  serv->Notify(true);
2057  mIPCServ = std::move(serv);
2058 
2059  // Save the port number in shared memory so that clients
2060  // know where to connect.
2061  mIPCServ->GetLocal(addr);
2062  *portnum = addr.Service();
2063  }
2064 
2065  // Now that the server is active, we release the LOCK semaphore
2066  // to allow any waiters to continue. The SERVER semaphore will
2067  // remain locked for the duration of this processes execution
2068  // and will be cleaned up by the system.
2069  op.sem_num = 0;
2070  op.sem_op = 1;
2071  semop(lockid, &op, 1);
2072 
2073  // Bail if the server creation failed.
2074  if (mIPCServ == nullptr)
2075  {
2077  XO("The Audacity IPC server failed to initialize.\n\n"
2078  "This is likely due to a resource shortage\n"
2079  "and a reboot may be required."),
2080  XO("Audacity Startup Failure"),
2081  wxOK | wxICON_ERROR);
2082 
2083  return false;
2084  }
2085 
2086  // We've successfully created the socket server and the app
2087  // should continue to initialize.
2088  return true;
2089  }
2090 
2091  // Retrieve the port number that the server is listening on.
2092  addr.Service(*portnum);
2093 
2094  // Now release the LOCK semaphore.
2095  op.sem_num = 0;
2096  op.sem_op = 1;
2097  semop(lockid, &op, 1);
2098 
2099  // If we get here, then Audacity is currently active. So, we connect
2100  // to it and we forward all filenames listed on the command line to
2101  // the active process.
2102 
2103  // Setup the socket
2104  //
2105  // A wxSocketClient must not be deleted by us, but rather, let the
2106  // framework do appropriate delayed deletion after Destroy()
2107  Destroy_ptr<wxSocketClient> sock { safenew wxSocketClient() };
2108  sock->SetFlags(wxSOCKET_WAITALL);
2109 
2110  // Attempt to connect to an active Audacity.
2111  sock->Connect(addr, true);
2112  if (!sock->IsConnected())
2113  {
2114  // All attempts to become the server or connect to one have failed. Not
2115  // sure what we can say about the error, but it's probably not because
2116  // Audacity is already running.
2118  XO("An unrecoverable error has occurred during startup"),
2119  XO("Audacity Startup Failure"),
2120  wxOK | wxICON_ERROR);
2121 
2122  return false;
2123  }
2124 
2125  // Parse the command line to ensure correct syntax, but ignore
2126  // options other than -v, and only use the filenames, if any.
2127  auto parser = ParseCommandLine();
2128  if (!parser)
2129  {
2130  // Complaints have already been made
2131  return false;
2132  }
2133 
2134  // Display Audacity's version if requested
2135  if (parser->Found(wxT("v")))
2136  {
2137  wxPrintf("Audacity v%s\n", AUDACITY_VERSION_STRING);
2138 
2139  return false;
2140  }
2141 
2142 #if defined(__WXMAC__)
2143  // On macOS the client gets events from the wxWidgets framework that
2144  // go to AudacityApp::MacOpenFile. Forward the file names to the prior
2145  // instance via the socket.
2146  for (const auto &filename: ofqueue)
2147  {
2148  auto str = filename.c_str().AsWChar();
2149  sock->WriteMsg(str, (filename.length() + 1) * sizeof(*str));
2150  }
2151 #endif
2152 
2153  // On macOS and Linux, forward any file names found in the command
2154  // line arguments.
2155  for (size_t j = 0, cnt = parser->GetParamCount(); j < cnt; ++j)
2156  {
2157  wxFileName filename(parser->GetParam(j));
2158  if (filename.MakeAbsolute())
2159  {
2160  const wxString param = filename.GetLongPath();
2161  sock->WriteMsg((const wxChar *) param, (param.length() + 1) * sizeof(wxChar));
2162  }
2163  }
2164 
2165  // Send an empty string to force existing Audacity to front
2166  sock->WriteMsg(wxEmptyString, sizeof(wxChar));
2167 
2168  // We've forwarded all of the filenames, so let the caller know
2169  // to terminate.
2170  return false;
2171 }
2172 
2173 void AudacityApp::OnServerEvent(wxSocketEvent & /* evt */)
2174 {
2175  wxSocketBase *sock;
2176 
2177  // Accept all pending connection requests
2178  do
2179  {
2180  sock = mIPCServ->Accept(false);
2181  if (sock)
2182  {
2183  // Setup the socket
2184  sock->SetEventHandler(*this, ID_IPC_SOCKET);
2185  sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
2186  sock->Notify(true);
2187  }
2188  } while (sock);
2189 }
2190 
2191 void AudacityApp::OnSocketEvent(wxSocketEvent & evt)
2192 {
2193  wxSocketBase *sock = evt.GetSocket();
2194 
2195  if (evt.GetSocketEvent() == wxSOCKET_LOST)
2196  {
2197  sock->Destroy();
2198  return;
2199  }
2200 
2201  // Read the length of the filename and bail if we have a short read
2202  wxChar name[PATH_MAX];
2203  sock->ReadMsg(&name, sizeof(name));
2204  if (!sock->Error())
2205  {
2206  // Add the filename to the queue. It will be opened by
2207  // the OnTimer() event when it is safe to do so.
2208  ofqueue.push_back(name);
2209  }
2210 }
2211 
2212 #endif
2213 
2214 std::unique_ptr<wxCmdLineParser> AudacityApp::ParseCommandLine()
2215 {
2216  auto parser = std::make_unique<wxCmdLineParser>(argc, argv);
2217  if (!parser)
2218  {
2219  return nullptr;
2220  }
2221 
2222  /*i18n-hint: This controls the number of bytes that Audacity will
2223  * use when writing files to the disk */
2224  parser->AddOption(wxT("b"), wxT("blocksize"), _("set max disk block size in bytes"),
2225  wxCMD_LINE_VAL_NUMBER);
2226 
2227  const auto journalOptionDescription =
2228  /*i18n-hint: brief help message for Audacity's command-line options
2229  A journal contains a sequence of user interface interactions to be repeated
2230  "log," "trail," "trace" have somewhat similar meanings */
2231  _("replay a journal file");
2232 
2233  parser->AddOption(wxT("j"), wxT("journal"), journalOptionDescription);
2234 
2235  /*i18n-hint: This displays a list of available options */
2236  parser->AddSwitch(wxT("h"), wxT("help"), _("this help message"),
2237  wxCMD_LINE_OPTION_HELP);
2238 
2239  /*i18n-hint: This runs a set of automatic tests on Audacity itself */
2240  parser->AddSwitch(wxT("t"), wxT("test"), _("run self diagnostics"));
2241 
2242  /*i18n-hint: This displays the Audacity version */
2243  parser->AddSwitch(wxT("v"), wxT("version"), _("display Audacity version"));
2244 
2245  /*i18n-hint: This is a list of one or more files that Audacity
2246  * should open upon startup */
2247  parser->AddParam(_("audio or project file name"),
2248  wxCMD_LINE_VAL_STRING,
2249  wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL);
2250 
2251  // Run the parser
2252  if (parser->Parse() == 0)
2253  return parser;
2254 
2255  return{};
2256 }
2257 
2258 void AudacityApp::OnQueryEndSession(wxCloseEvent & event)
2259 {
2260  bool mustVeto = false;
2261 
2262 #ifdef __WXMAC__
2263  mustVeto = wxDialog::OSXHasModalDialogsOpen();
2264 #endif
2265 
2266  if ( mustVeto )
2267  event.Veto(true);
2268  else
2269  OnEndSession(event);
2270 }
2271 
2272 void AudacityApp::OnEndSession(wxCloseEvent & event)
2273 {
2274  bool force = !event.CanVeto();
2275 
2276  // Try to close each open window. If the user hits Cancel
2277  // in a Save Changes dialog, don't continue.
2278  gIsQuitting = true;
2279  if (AllProjects{}.size())
2280  // PRL: Always did at least once before close might be vetoed
2281  // though I don't know why that is important
2283  bool closedAll = CloseAllProjects( force );
2284  if ( !closedAll )
2285  {
2286  gIsQuitting = false;
2287  event.Veto();
2288  }
2289 }
2290 
2292 {
2293  gIsQuitting = true;
2294  while(Pending())
2295  {
2296  Dispatch();
2297  }
2298 
2300 
2301  if(gPrefs)
2302  {
2303  bool bFalse = false;
2304  //Should we change the commands.cfg location next startup?
2305  if(gPrefs->Read(wxT("/QDeleteCmdCfgLocation"), &bFalse))
2306  {
2307  gPrefs->DeleteEntry(wxT("/QDeleteCmdCfgLocation"));
2308  gPrefs->Write(wxT("/DeleteCmdCfgLocation"), true);
2309  gPrefs->Flush();
2310  }
2311  }
2312 
2314 
2316 
2317  DeinitFFT();
2318 
2319 #ifdef HAS_NETWORKING
2321 #endif
2322 
2323  AudioIO::Deinit();
2324 
2326 
2327  // Terminate the PluginManager (must be done before deleting the locale)
2329 
2330  return 0;
2331 }
2332 
2333 // The following five methods are currently only used on Mac OS,
2334 // where it's possible to have a menu bar but no windows open.
2335 // It doesn't hurt any other platforms, though.
2336 
2337 // ...That is, as long as you check to see if no windows are open
2338 // before executing the stuff.
2339 // To fix this, check to see how many project windows are open,
2340 // and skip the event unless none are open (which should only happen
2341 // on the Mac, at least currently.)
2342 
2343 void AudacityApp::OnMenuAbout(wxCommandEvent & /*event*/)
2344 {
2345  // This function shadows a similar function
2346  // in Menus.cpp, but should only be used on the Mac platform.
2347 #ifdef __WXMAC__
2348  // Modeless dialog, consistent with other Mac applications
2349  // Not more than one at once!
2350  const auto instance = AboutDialog::ActiveIntance();
2351  if (instance)
2352  instance->Raise();
2353  else
2354  // This dialog deletes itself when dismissed
2355  (safenew AboutDialog{ nullptr })->Show(true);
2356 #else
2357  wxASSERT(false);
2358 #endif
2359 }
2360 
2361 void AudacityApp::OnMenuNew(wxCommandEvent & event)
2362 {
2363  // This function shadows a similar function
2364  // in Menus.cpp, but should only be used on the Mac platform
2365  // when no project windows are open. This check assures that
2366  // this happens, and enable the same code to be present on
2367  // all platforms.
2368 
2369  if(AllProjects{}.empty())
2370  (void) ProjectManager::New();
2371  else
2372  event.Skip();
2373 }
2374 
2375 
2376 void AudacityApp::OnMenuOpen(wxCommandEvent & event)
2377 {
2378  // This function shadows a similar function
2379  // in Menus.cpp, but should only be used on the Mac platform
2380  // when no project windows are open. This check assures that
2381  // this happens, and enable the same code to be present on
2382  // all platforms.
2383 
2384 
2385  if(AllProjects{}.empty())
2387  else
2388  event.Skip();
2389 
2390 
2391 }
2392 
2393 void AudacityApp::OnMenuPreferences(wxCommandEvent & event)
2394 {
2395  // This function shadows a similar function
2396  // in Menus.cpp, but should only be used on the Mac platform
2397  // when no project windows are open. This check assures that
2398  // this happens, and enable the same code to be present on
2399  // all platforms.
2400 
2401  if(AllProjects{}.empty()) {
2402  GlobalPrefsDialog dialog(nullptr /* parent */, nullptr );
2403  dialog.ShowModal();
2404  }
2405  else
2406  event.Skip();
2407 
2408 }
2409 
2410 void AudacityApp::OnMenuExit(wxCommandEvent & event)
2411 {
2412  // This function shadows a similar function
2413  // in Menus.cpp, but should only be used on the Mac platform
2414  // when no project windows are open. This check assures that
2415  // this happens, and enable the same code to be present on
2416  // all platforms.
2417 
2418  // LL: Removed "if" to allow closing based on final project count.
2419  // if(AllProjects{}.empty())
2420  QuitAudacity();
2421 
2422  // LL: Veto quit if projects are still open. This can happen
2423  // if the user selected Cancel in a Save dialog.
2424  event.Skip(AllProjects{}.empty());
2425 
2426 }
2427 
2428 #ifndef __WXMAC__
2430 {
2431  // Currently this is implemented only on macOS
2432 }
2433 #endif
2434 
2435 //BG: On Windows, associate the aup file type with Audacity
2436 /* We do this in the Windows installer now,
2437  to avoid issues where user doesn't have admin privileges, but
2438  in case that didn't work, allow the user to decide at startup.
2439 
2440  //v Should encapsulate this & allow access from Prefs, too,
2441  // if people want to manually change associations.
2442 */
2443 #if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
2444 void AudacityApp::AssociateFileTypes()
2445 {
2446  // Check pref in case user has already decided against it.
2447  bool bWantAssociateFiles = true;
2448  if (gPrefs->Read(wxT("/WantAssociateFiles"), &bWantAssociateFiles) &&
2449  !bWantAssociateFiles)
2450  {
2451  // User has already decided against it
2452  return;
2453  }
2454 
2455  wxRegKey associateFileTypes;
2456 
2457  auto IsDefined = [&](const wxString &type)
2458  {
2459  associateFileTypes.SetName(wxString::Format(wxT("HKCR\\%s"), type));
2460  bool bKeyExists = associateFileTypes.Exists();
2461  if (!bKeyExists)
2462  {
2463  // Not at HKEY_CLASSES_ROOT. Try HKEY_CURRENT_USER.
2464  associateFileTypes.SetName(wxString::Format(wxT("HKCU\\Software\\Classes\\%s"), type));
2465  bKeyExists = associateFileTypes.Exists();
2466  }
2467  return bKeyExists;
2468  };
2469 
2470  auto DefineType = [&](const wxString &type)
2471  {
2472  wxString root_key = wxT("HKCU\\Software\\Classes\\");
2473 
2474  // Start with HKEY_CLASSES_CURRENT_USER.
2475  associateFileTypes.SetName(wxString::Format(wxT("%s%s"), root_key, type));
2476  if (!associateFileTypes.Create(true))
2477  {
2478  // Not at HKEY_CLASSES_CURRENT_USER. Try HKEY_CURRENT_ROOT.
2479  root_key = wxT("HKCR\\");
2480  associateFileTypes.SetName(wxString::Format(wxT("%s%s"), root_key, type));
2481  if (!associateFileTypes.Create(true))
2482  {
2483  // Actually, can't create keys. Empty root_key to flag failure.
2484  root_key.empty();
2485  }
2486  }
2487 
2488  if (!root_key.empty())
2489  {
2490  associateFileTypes = wxT("Audacity.Project"); // Finally set value for the key
2491  }
2492 
2493  return root_key;
2494  };
2495 
2496  // Check for legacy and UP types
2497  if (IsDefined(wxT(".aup3")) && IsDefined(wxT(".aup")) && IsDefined(wxT("Audacity.Project")))
2498  {
2499  // Already defined, so bail
2500  return;
2501  }
2502 
2503  // File types are not currently associated.
2504  int wantAssoc =
2506  XO(
2507 "Audacity project (.aup3) files are not currently \nassociated with Audacity. \n\nAssociate them, so they open on double-click?"),
2508  XO("Audacity Project Files"),
2509  wxYES_NO | wxICON_QUESTION);
2510 
2511  if (wantAssoc == wxNO)
2512  {
2513  // User said no. Set a pref so we don't keep asking.
2514  gPrefs->Write(wxT("/WantAssociateFiles"), false);
2515  gPrefs->Flush();
2516  return;
2517  }
2518 
2519  // Show that user wants associations
2520  gPrefs->Write(wxT("/WantAssociateFiles"), true);
2521  gPrefs->Flush();
2522 
2523  wxString root_key;
2524 
2525  root_key = DefineType(wxT(".aup3"));
2526  if (root_key.empty())
2527  {
2528  //v Warn that we can't set keys. Ask whether to set pref for no retry?
2529  }
2530  else
2531  {
2532  DefineType(wxT(".aup"));
2533 
2534  associateFileTypes = wxT("Audacity.Project"); // Finally set value for .AUP key
2535  associateFileTypes.SetName(root_key + wxT("Audacity.Project"));
2536  if (!associateFileTypes.Exists())
2537  {
2538  associateFileTypes.Create(true);
2539  associateFileTypes = wxT("Audacity Project File");
2540  }
2541 
2542  associateFileTypes.SetName(root_key + wxT("Audacity.Project\\shell"));
2543  if (!associateFileTypes.Exists())
2544  {
2545  associateFileTypes.Create(true);
2546  associateFileTypes = wxT("");
2547  }
2548 
2549  associateFileTypes.SetName(root_key + wxT("Audacity.Project\\shell\\open"));
2550  if (!associateFileTypes.Exists())
2551  {
2552  associateFileTypes.Create(true);
2553  }
2554 
2555  associateFileTypes.SetName(root_key + wxT("Audacity.Project\\shell\\open\\command"));
2556  wxString tmpRegAudPath;
2557  if(associateFileTypes.Exists())
2558  {
2559  tmpRegAudPath = associateFileTypes.QueryDefaultValue().Lower();
2560  }
2561 
2562  if (!associateFileTypes.Exists() ||
2563  (tmpRegAudPath.Find(wxT("audacity.exe")) >= 0))
2564  {
2565  associateFileTypes.Create(true);
2566  associateFileTypes = (wxString)argv[0] + (wxString)wxT(" \"%1\"");
2567  }
2568 
2569 #if 0
2570  // These can be use later to support more startup messages
2571  // like maybe "Import into existing project" or some such.
2572  // Leaving here for an example...
2573  associateFileTypes.SetName(root_key + wxT("Audacity.Project\\shell\\open\\ddeexec"));
2574  if (!associateFileTypes.Exists())
2575  {
2576  associateFileTypes.Create(true);
2577  associateFileTypes = wxT("%1");
2578  }
2579 
2580  associateFileTypes.SetName(root_key + wxT("Audacity.Project\\shell\\open\\ddeexec\\Application"));
2581  if (!associateFileTypes.Exists())
2582  {
2583  associateFileTypes.Create(true);
2584  associateFileTypes = IPC_APPL;
2585  }
2586 
2587  associateFileTypes.SetName(root_key + wxT("Audacity.Project\\shell\\open\\ddeexec\\Topic"));
2588  if (!associateFileTypes.Exists())
2589  {
2590  associateFileTypes.Create(true);
2591  associateFileTypes = IPC_TOPIC;
2592  }
2593 #endif
2594  }
2595 }
2596 #endif
2597 
FileNames::ResourcesDir
FILES_API FilePath ResourcesDir()
Journal::SetInputFileName
void SetInputFileName(const wxString &path)
Definition: Journal.cpp:136
PrefsDialog::ShowModal
int ShowModal() override
Definition: PrefsDialog.cpp:596
AppName
const std::wstring AppName
This program's name.
Definition: ModuleConstants.cpp:15
FileConfig::SetPath
virtual void SetPath(const wxString &strPath) wxOVERRIDE
Definition: FileConfig.cpp:93
ID_IPC_SOCKET
#define ID_IPC_SOCKET
Definition: AudacityApp.cpp:820
AllProjects::begin
const_iterator begin() const
Definition: Project.cpp:24
ID_IPC_SERVER
#define ID_IPC_SERVER
Definition: AudacityApp.cpp:819
TranslatableString::empty
bool empty() const
Definition: TranslatableString.h:72
TempDirectory::DefaultTempDir
FILES_API const FilePath & DefaultTempDir()
Definition: TempDirectory.cpp:58
AudacityApp::OnMRUClear
void OnMRUClear(wxCommandEvent &event)
Definition: AudacityApp.cpp:908
ProjectAudioIO::GetAudioIOToken
int GetAudioIOToken() const
Definition: ProjectAudioIO.cpp:41
Scrubber::Get
static Scrubber & Get(AudacityProject &project)
Definition: Scrubbing.cpp:201
wxGetApp
AudacityApp & wxGetApp()
AudacityApp::OnExit
int OnExit(void) override
Definition: AudacityApp.cpp:2291
SetToExtantDirectory
void SetToExtantDirectory(wxString &result, const wxString &dir)
Definition: AudacityApp.cpp:1718
FileHistory::ID_RECENT_FIRST
@ ID_RECENT_FIRST
Definition: FileHistory.h:36
ProjectFileIO.h
ProjectAudioManager::Get
static ProjectAudioManager & Get(AudacityProject &project)
Definition: ProjectAudioManager.cpp:55
OSFILENAME
#define OSFILENAME(X)
Protect against Unicode to multi-byte conversion failures on Windows.
Definition: SelectFile.h:54
ScoreAlignDialog.h
AudacityApp::InitPart2
bool InitPart2()
Definition: AudacityApp.cpp:1373
FileNames::MkDir
FILES_API wxString MkDir(const wxString &Str)
AudacityMessageBox
int AudacityMessageBox(const TranslatableString &message, const TranslatableString &caption, long style, wxWindow *parent, int x, int y)
Definition: AudacityMessageBox.cpp:17
fn
static const auto fn
Definition: WaveformView.cpp:1108
AudacityApp
AudacityApp is the 'main' class for Audacity.
Definition: AudacityApp.h:36
AppCommandEvent.h
Headers and event table macros for AppCommandEvent.
AudacityApp::InitTempDir
bool InitTempDir()
Definition: AudacityApp.cpp:1732
TempDirectory::ResetTempDir
FILES_API void ResetTempDir()
Definition: TempDirectory.cpp:50
ProjectSettings::GetShowSplashScreen
bool GetShowSplashScreen() const
Definition: ProjectSettings.h:132
gPrefs
FileConfig * gPrefs
Definition: Prefs.cpp:70
FFmpeg.h
AudacityApp::OnMenuExit
void OnMenuExit(wxCommandEvent &event)
Definition: AudacityApp.cpp:2410
AudacityApp::ParseCommandLine
std::unique_ptr< wxCmdLineParser > ParseCommandLine()
Definition: AudacityApp.cpp:2214
Project.h
str
#define str(a)
Definition: DBConnection.cpp:30
Import.h
AboutDialog
The AboutDialog shows the program version and developer credits.
Definition: AboutDialog.h:32
Importer::Get
static Importer & Get()
Definition: Import.cpp:71
ModuleManager.h
Clipboard.h
FileNames::UpdateDefaultPath
FILES_API void UpdateDefaultPath(Operation op, const FilePath &path)
SplashDialog.h
UpdateManager::Start
static void Start()
Definition: UpdateManager.cpp:60
Format
Abstract base class used in importing a file.
FileHistory::Clear
void Clear()
Definition: FileHistory.cpp:90
UpdateManager.h
Declare a class that handles managing of updates.
FinishPreferences
void FinishPreferences()
Definition: Prefs.cpp:228
Journal::Dispatch
bool Dispatch()
Definition: Journal.cpp:202
Clipboard::Clear
void Clear()
Definition: Clipboard.cpp:41
PreferredSystemAppearance
PreferredSystemAppearance
A system theme, that matches selected theme best (only works on macOS with builtin themes).
Definition: Theme.h:31
AudacityApp::CreateSingleInstanceChecker
bool CreateSingleInstanceChecker(const wxString &dir)
PrefsDialog.h
AudacityApp::SafeMRUOpen
bool SafeMRUOpen(const wxString &fileName)
Definition: AudacityApp.cpp:903
RunBenchmark
void RunBenchmark(wxWindow *parent, AudacityProject &project)
Definition: Benchmark.cpp:95
FileConfig.h
MallocString
std::unique_ptr< Character[], freer > MallocString
Definition: MemoryX.h:274
FileConfig::DeleteEntry
virtual bool DeleteEntry(const wxString &key, bool bDeleteGroupIfEmpty=true) wxOVERRIDE
Definition: FileConfig.cpp:209
XO
#define XO(s)
Definition: Internat.h:31
GetActiveProject
AUDACITY_DLL_API std::weak_ptr< AudacityProject > GetActiveProject()
Definition: ActiveProject.cpp:24
DirectoriesPrefs.h
AudacityApp::OnQueryEndSession
void OnQueryEndSession(wxCloseEvent &event)
Definition: AudacityApp.cpp:2258
ProjectSettings::Get
static ProjectSettings & Get(AudacityProject &project)
Definition: ProjectSettings.cpp:44
AudacityApp::OnMenuAbout
void OnMenuAbout(wxCommandEvent &event)
Definition: AudacityApp.cpp:2343
CloseAllProjects
static bool CloseAllProjects(bool force)
Definition: AudacityApp.cpp:428
FileHistory
Similar to wxFileHistory, but customized to our needs.
Definition: FileHistory.h:26
AudacityApp::OnEndSession
void OnEndSession(wxCloseEvent &event)
Definition: AudacityApp.cpp:2272
IPCConn::OnExec
bool OnExec(const wxString &WXUNUSED(topic), const wxString &data)
Definition: AudacityApp.cpp:718
ProjectSettings.h
ProjectWindow::Get
static ProjectWindow & Get(AudacityProject &project)
Definition: ProjectWindow.cpp:535
AudacityApp::OnServerEvent
void OnServerEvent(wxSocketEvent &evt)
BasicUI::CallAfter
void CallAfter(Action action)
Schedule an action to be done later, and in the main thread.
Definition: BasicUI.cpp:38
Languages::GetLocaleName
wxString GetLocaleName()
Definition: Languages.cpp:390
FileHistory::ID_RECENT_CLEAR
@ ID_RECENT_CLEAR
Definition: FileHistory.h:35
IPCConn::IPCConn
IPCConn()
Definition: AudacityApp.cpp:709
FileConfig::GetFirstGroup
virtual bool GetFirstGroup(wxString &str, long &lIndex) const wxOVERRIDE
Definition: FileConfig.cpp:103
AudacityApp::mIPCServ
std::unique_ptr< wxSocketServer > mIPCServ
Definition: AudacityApp.h:115
ProjectManager::OpenProject
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.
Definition: ProjectManager.cpp:949
ProjectAudioManager.h
ProjectAudioIO::Get
static ProjectAudioIO & Get(AudacityProject &project)
Definition: ProjectAudioIO.cpp:22
wxArrayStringEx
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
Definition: wxArrayStringEx.h:18
FileNames::PreferenceKey
FILES_API wxString PreferenceKey(FileNames::Operation op, FileNames::PathType type)
ProjectManager::SaveWindowSize
static void SaveWindowSize()
Definition: ProjectManager.cpp:110
MenuCreator::RebuildAllMenuBars
static void RebuildAllMenuBars()
Definition: Menus.cpp:679
FileHistory::Global
static FileHistory & Global()
Definition: FileHistory.cpp:37
Sequence::SetMaxDiskBlockSize
static void SetMaxDiskBlockSize(size_t bytes)
Definition: Sequence.cpp:1948
FileNames::AddUniquePathToPathList
FILES_API void AddUniquePathToPathList(const FilePath &path, FilePaths &pathList)
Journal::Begin
bool Begin(const FilePath &dataDir)
Definition: Journal.cpp:141
IPCServ::IPCServ
IPCServ(const wxString &appl)
Definition: AudacityApp.cpp:732
AllProjects::empty
bool empty() const
Definition: Project.h:46
AudacityApp::SetPreferredSystemAppearance
void SetPreferredSystemAppearance(PreferredSystemAppearance appearance)
Definition: AudacityApp.cpp:2429
Journal::GetExitCode
int GetExitCode()
Definition: Journal.cpp:288
DirectoriesPrefsFactory
PrefsPanel::Factory DirectoriesPrefsFactory()
Definition: DirectoriesPrefs.cpp:521
SplashDialog::DoHelpWelcome
static void DoHelpWelcome(AudacityProject &project)
Definition: SplashDialog.cpp:105
gInited
static bool gInited
Definition: AudacityApp.cpp:425
AudacityApp::mTimer
wxTimer mTimer
Definition: AudacityApp.h:103
CommandManager::RemoveDuplicateShortcuts
void RemoveDuplicateShortcuts()
Definition: CommandManager.cpp:1677
EVT_APP_COMMAND
#define EVT_APP_COMMAND(winid, fn)
Definition: AppCommandEvent.h:53
FileNames::DataDir
FILES_API FilePath DataDir()
Audacity user data directory.
AboutDialog::ActiveIntance
static AboutDialog * ActiveIntance()
CommandHandler.h
Contains declarations for the CommandHandler class.
AllProjects::size
size_t size() const
Definition: Project.cpp:19
AudacityApp::OnSocketEvent
void OnSocketEvent(wxSocketEvent &evt)
Journal.h
FFT.h
GUIPrefs::SetLang
static wxString SetLang(const wxString &lang)
Definition: GUIPrefs.cpp:253
AudacityApp::MRUOpen
bool MRUOpen(const FilePath &fileName)
FileConfig::GetNextGroup
virtual bool GetNextGroup(wxString &str, long &lIndex) const wxOVERRIDE
Definition: FileConfig.cpp:108
ResetPreferences
void ResetPreferences()
Call this to reset preferences to an (almost)-"new" default state.
Definition: Prefs.cpp:209
ModuleManager::Dispatch
int Dispatch(ModuleDispatchTypes type)
Definition: ModuleManager.cpp:381
AudacityException
Base class for exceptions specially processed by the application.
Definition: AudacityException.h:33
AppQuiting
@ AppQuiting
Definition: ModuleConstants.h:31
InitPreferences
void InitPreferences(std::unique_ptr< FileConfig > uPrefs)
Definition: Prefs.cpp:202
wxWidgetsBasicUI
An implementation of BasicUI::Services in terms of the wxWidgets toolkit.
Definition: wxWidgetsBasicUI.h:20
FilePath
wxString FilePath
Definition: Project.h:20
NetworkManager.h
Declare a class for preforming HTTP requests.
AudacityApp::OnReceiveCommand
void OnReceiveCommand(AppCommandEvent &event)
Definition: AudacityApp.cpp:1685
ofqueue
static wxArrayString ofqueue
Definition: AudacityApp.cpp:696
FileNames::SetAudacityPathList
FILES_API void SetAudacityPathList(FilePaths list)
BasicUI::Get
Services * Get()
Fetch the global instance, or nullptr if none is yet installed.
Definition: BasicUI.cpp:26
PluginManager.h
TrackList::ClearPendingTracks
void ClearPendingTracks(ListOfTracks *pAdded=nullptr)
Definition: Track.cpp:1090
ShowAutoRecoveryDialogIfNeeded
bool ShowAutoRecoveryDialogIfNeeded(AudacityProject *&pproj, bool *didRecoverAnything)
Definition: AutoRecoveryDialog.cpp:450
AudacityApp::mCmdHandler
std::unique_ptr< CommandHandler > mCmdHandler
Definition: AudacityApp.h:99
AudacityApp::OnKeyDown
void OnKeyDown(wxKeyEvent &event)
Definition: AudacityApp.cpp:1691
AudacityFileConfig::Create
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.
Definition: AudacityFileConfig.cpp:36
AudacityApp.h
ModuleManager::Get
static ModuleManager & Get()
Definition: ModuleManager.cpp:395
Theme.h
Languages.h
KeyConfigPrefsFactory
PrefsPanel::Factory KeyConfigPrefsFactory(const CommandID &name)
Definition: KeyConfigPrefs.cpp:941
audacity::network_manager::NetworkManager::GetInstance
static NetworkManager & GetInstance()
Definition: NetworkManager.cpp:36
AudacityApp::OnMRUFile
void OnMRUFile(wxCommandEvent &event)
Definition: AudacityApp.cpp:916
name
const TranslatableString name
Definition: Distortion.cpp:98
ProjectManager::New
static AudacityProject * New()
Definition: ProjectManager.cpp:529
SelectFile.h
FileConfig::SetVersionKeysInit
void SetVersionKeysInit(int major, int minor, int micro)
Definition: FileConfig.h:50
AudacityLogger::Get
static AudacityLogger * Get()
Definition: AudacityLogger.cpp:35
audacity::network_manager::NetworkManager::Terminate
static void Terminate()
Definition: NetworkManager.cpp:43
EVT_MENU
EVT_MENU(OnSetPlayRegionToSelectionID, AdornedRulerPanel::OnSetPlayRegionToSelection) EVT_COMMAND(OnTogglePinnedStateID
Scrubbing.h
AudacityApp::OnMenuPreferences
void OnMenuPreferences(wxCommandEvent &event)
Definition: AudacityApp.cpp:2393
AudacityFileConfig.h
ProjectFileManager.h
PluginManager::Initialize
void Initialize()
Definition: PluginManager.cpp:705
ASlider.h
FileNames::ModulesDir
FILES_API FilePath ModulesDir()
TempDirectory.h
IPCServ
Definition: AudacityApp.cpp:730
AudacityApp::OnMenuNew
void OnMenuNew(wxCommandEvent &event)
Definition: AudacityApp.cpp:2361
ProjectAudioManager::Stop
void Stop(bool stopStream=true)
Definition: ProjectAudioManager.cpp:495
Importer::Initialize
bool Initialize()
Definition: Import.cpp:132
TempDirectory::IsTempDirectoryNameOK
FILES_API bool IsTempDirectoryNameOK(const FilePath &Name)
Definition: TempDirectory.cpp:70
FileConfig::GetVersionKeysInit
void GetVersionKeysInit(int &major, int &minor, int &micro) const
Definition: FileConfig.h:56
AudacityApp::AudacityApp
AudacityApp()
Definition: AudacityApp.cpp:1058
ProjectFileIO::InitializeSQL
static bool InitializeSQL()
Definition: ProjectFileIO.cpp:211
IPC_TOPIC
#define IPC_TOPIC
Definition: AudacityApp.cpp:704
ProjectManager.h
AUDACITY_PREFS_VERSION_STRING
#define AUDACITY_PREFS_VERSION_STRING
Definition: Prefs.h:35
Menus.h
theTheme
THEME_API Theme theTheme
Definition: Theme.cpp:79
Importer::Terminate
bool Terminate()
Definition: Import.cpp:171
ProjectWindows.h
accessors for certain important windows associated with each project
FileNames::AddMultiPathsToPathList
FILES_API void AddMultiPathsToPathList(const wxString &multiPathString, FilePaths &pathList)
AudacityLogger.h
FileConfig::DeleteGroup
virtual bool DeleteGroup(const wxString &key) wxOVERRIDE
Definition: FileConfig.cpp:219
IPC_APPL
#define IPC_APPL
Definition: AudacityApp.cpp:703
TempDirectory::SetDefaultTempDir
FILES_API void SetDefaultTempDir(const FilePath &tempDir)
Definition: TempDirectory.cpp:63
ThemeBase::SetOnPreferredSystemAppearanceChanged
OnPreferredSystemAppearanceChanged SetOnPreferredSystemAppearanceChanged(OnPreferredSystemAppearanceChanged handler)
Definition: Theme.cpp:1294
Clipboard::Get
static Clipboard & Get()
Definition: Clipboard.cpp:29
PluginManager::Get
static PluginManager & Get()
Definition: PluginManager.cpp:695
AppInitialized
@ AppInitialized
Definition: ModuleConstants.h:30
ProjectFileManager::IsAlreadyOpen
static bool IsAlreadyOpen(const FilePath &projPathName)
Definition: ProjectFileManager.cpp:847
AColor::Init
static void Init()
Definition: AColor.cpp:465
FileConfig::Flush
virtual bool Flush(bool bCurrentOnly=false) wxOVERRIDE
Definition: FileConfig.cpp:143
PlatformCompatibility.h
key
static const AudacityProject::AttachedObjects::RegisteredFactory key
Definition: CommandManager.cpp:201
FileNames::AudacityPathList
FILES_API const FilePaths & AudacityPathList()
A list of directories that should be searched for Audacity files (plug-ins, help files,...
TrackList::Get
static TrackList & Get(AudacityProject &project)
Definition: Track.cpp:506
FileHistory.h
TaggedIdentifier< CommandIdTag, false >
_
#define _(s)
Definition: Internat.h:75
ProjectHistory::RollbackState
void RollbackState()
Definition: ProjectHistory.cpp:117
AudioIO.h
AudacityProject
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:92
IPCConn::~IPCConn
~IPCConn()
Definition: AudacityApp.cpp:714
AudacityApp::InitCommandHandler
void InitCommandHandler()
Definition: AudacityApp.cpp:1678
ModuleManager::Initialize
void Initialize()
Definition: ModuleManager.cpp:354
GUIPrefs.h
kAudacityAppTimerID
#define kAudacityAppTimerID
Definition: AudacityApp.cpp:823
InitDitherers
void InitDitherers()
Definition: SampleFormat.cpp:53
CommandManager::SetMenuHook
static MenuHook SetMenuHook(const MenuHook &hook)
Definition: CommandManager.cpp:223
AudacityException::DelayedHandlerAction
virtual void DelayedHandlerAction()=0
Action to do in the main thread at idle time of the event loop.
AudacityMessageBox.h
GetProjectFrame
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 ...
Definition: ProjectWindows.cpp:72
wxWidgetsBasicUI.h
Implementation of BasicUI using wxWidgets.
AllProjects
Definition: Project.h:35
AudioIO::Init
static void Init()
Definition: AudioIO.cpp:237
AutoRecoveryDialog.h
ProjectHistory.h
AudacityApp::OnExceptionInMainLoop
bool OnExceptionInMainLoop() override
Definition: AudacityApp.cpp:1008
Sequence.h
CloseScreenshotTools
void CloseScreenshotTools()
Definition: Screenshot.cpp:150
ActiveProject.h
Handle changing of active project and keep global project pointer.
AboutDialog.h
CrashReport.h
AudacityApp::OnMenuOpen
void OnMenuOpen(wxCommandEvent &event)
Definition: AudacityApp.cpp:2376
ProjectManager::OpenFiles
static void OpenFiles(AudacityProject *proj)
Definition: ProjectManager.cpp:866
GetNextWindowPlacement
void GetNextWindowPlacement(wxRect *nextRect, bool *pMaximized, bool *pIconized)
Definition: ProjectWindow.cpp:139
AudacityApp::OnIdle
void OnIdle(wxIdleEvent &)
Definition: AudacityApp.cpp:1662
GlobalPrefsDialog
Definition: PrefsDialog.h:81
Track.h
declares abstract base class Track, TrackList, and iterators over TrackList
FindProjectFrame
wxFrame * FindProjectFrame(AudacityProject *project)
Get a pointer to the window associated with a project, or null if the given pointer is null,...
Definition: ProjectWindows.cpp:88
AudacityApp::OnTimer
void OnTimer(wxTimerEvent &event)
Definition: AudacityApp.cpp:933
IPCConn
Definition: AudacityApp.cpp:707
FFmpegStartup
void FFmpegStartup()
Definition: FFmpeg.cpp:65
ProjectWindow.h
IPCServ::OnAcceptConnection
wxConnectionBase * OnAcceptConnection(const wxString &topic) override
Definition: AudacityApp.cpp:742
AudacityApp::OnInit
bool OnInit(void) override
Definition: AudacityApp.cpp:1078
ProjectWindow::RedrawProject
void RedrawProject(const bool bForceWaveTracks=false)
Definition: ProjectWindow.cpp:710
Languages::GetSystemLanguageCode
wxString GetSystemLanguageCode(const FilePaths &pathList)
Definition: Languages.cpp:83
IPCServ::~IPCServ
~IPCServ()
Definition: AudacityApp.cpp:738
DeinitFFT
void DeinitFFT()
Definition: FFT.cpp:114
Benchmark.h
CommandManager::Get
static CommandManager & Get(AudacityProject &project)
Definition: CommandManager.cpp:207
anonymous_namespace{AudacityApp.cpp}::PopulatePreferences
void PopulatePreferences()
Definition: AudacityApp.cpp:189
MenuTable::DestroyRegistry
void DestroyRegistry()
Definition: Menus.cpp:271
WL
#define WL(lang, sublang)
Definition: AudacityApp.cpp:979
AudioIO::Deinit
static void Deinit()
Definition: AudioIO.cpp:264
AudacityApp::mChecker
std::unique_ptr< wxSingleInstanceChecker > mChecker
Definition: AudacityApp.h:101
ThemeBase::LoadPreferredTheme
static bool LoadPreferredTheme()
Definition: Theme.cpp:147
Destroy_ptr
std::unique_ptr< T, Destroyer< T > > Destroy_ptr
a convenience for using Destroyer
Definition: MemoryX.h:290
AudioIO::Get
static AudioIO * Get()
Definition: AudioIO.cpp:141
safenew
#define safenew
Definition: MemoryX.h:10
audacity::ToUTF8
std::string ToUTF8(const std::wstring &wstr)
Definition: CodeConversions.cpp:19
EVT_MENU_RANGE
EVT_MENU_RANGE(FileHistory::ID_RECENT_FIRST, FileHistory::ID_RECENT_LAST, AudacityApp::OnMRUFile) bool AudacityApp
Definition: AudacityApp.cpp:852
FileHistory::Save
void Save(wxConfigBase &config)
Definition: FileHistory.cpp:136
BasicUI::Install
Services * Install(Services *pInstance)
Install an implementation; return the previously installed instance.
Definition: BasicUI.cpp:28
AColor.h
PluginManager::Terminate
void Terminate()
Definition: PluginManager.cpp:730
END_EVENT_TABLE
END_EVENT_TABLE()
ProjectAudioIO.h
KeyConfigPrefs.h
Screenshot.h
AudacityApp::OnFatalException
void OnFatalException() override
Definition: AudacityApp.cpp:992
PrefsPanel::Factories
std::vector< PrefsPanel::PrefsNode > Factories
Definition: PrefsPanel.h:69
ProjectHistory::Get
static ProjectHistory & Get(AudacityProject &project)
Definition: ProjectHistory.cpp:26
ProjectManager::SetClosingAll
static void SetClosingAll(bool closing)
Definition: ProjectManager.cpp:613
gIsQuitting
static bool gIsQuitting
Definition: AudacityApp.cpp:426
AudacityApp::OnRun
int OnRun() override
Definition: AudacityApp.cpp:1652
AppCommandEvent
An event 'envelope' for sending Command objects through the wxwidgets event loop.
Definition: AppCommandEvent.h:30
FileConfig::GetPath
virtual const wxString & GetPath() const wxOVERRIDE
Definition: FileConfig.cpp:98
TempDirectory::TempDir
FILES_API wxString TempDir()
Definition: TempDirectory.cpp:26
QuitAudacity
static void QuitAudacity(bool bForce)
Definition: AudacityApp.cpp:449
AudacityApp::~AudacityApp
~AudacityApp()
Definition: AudacityApp.cpp:1072