mirror of
https://github.com/cookiengineer/audacity
synced 2025-12-19 15:11:23 +01:00
Should fix the single instance detection on OSX
The problem was that different temp directories can be specified when using Portable Settings. This caused the single instance checker to look for it's lock file in different locations so it was unable to detect that another instance was running. This changes the directory for the lock file to be the user's home directory (which is the default for the checker anyway). This allow the user to still specify different temp directories in the Portable Settings and ensure's that only one instance (per user) ever runs. It now checks the single instance before initializing preferences since preferences are modified during initialization which could interere with an already running instance. In addition, the Mac now uses the DDE IPC startup to ensure all files are opened by the single Audacity instance. Normally this is not needed since we also support the OSX mechanism for opening by an existing process. But, that only works if the exact same Audacity.app is used. There are instances when this is not always the case. I also ran across a problem with language initialization. Since preferences were initialized before the locale was set, dialogs would be shown in English. I've made a change that sets the language to the system language until the preferences are loaded and then resets it to the user selected language.
This commit is contained in:
@@ -564,8 +564,6 @@ GnomeShutdown GnomeShutdownInstance;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__WXMSW__) || defined(__WXGTK__)
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// DDE support for opening multiple files with one instance
|
// DDE support for opening multiple files with one instance
|
||||||
// of Audacity.
|
// of Audacity.
|
||||||
@@ -649,8 +647,6 @@ public:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __WXMAC__
|
#ifndef __WXMAC__
|
||||||
IMPLEMENT_APP(AudacityApp)
|
IMPLEMENT_APP(AudacityApp)
|
||||||
/* make the application class known to wxWidgets for dynamic construction */
|
/* make the application class known to wxWidgets for dynamic construction */
|
||||||
@@ -1041,9 +1037,6 @@ bool AudacityApp::OnInit()
|
|||||||
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
|
wxSystemOptions::SetOption( wxMAC_WINDOW_PLAIN_TRANSITION, 1 );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// LL: Moved here from InitPreferences() to ensure VST effect
|
|
||||||
// discovery writes configuration to the correct directory
|
|
||||||
// on OSX with case-sensitive file systems.
|
|
||||||
#ifdef AUDACITY_NAME
|
#ifdef AUDACITY_NAME
|
||||||
wxString appName = wxT(AUDACITY_NAME);
|
wxString appName = wxT(AUDACITY_NAME);
|
||||||
wxString vendorName = wxT(AUDACITY_NAME);
|
wxString vendorName = wxT(AUDACITY_NAME);
|
||||||
@@ -1063,6 +1056,20 @@ bool AudacityApp::OnInit()
|
|||||||
|
|
||||||
wxFileSystem::AddHandler(new wxZipFSHandler);
|
wxFileSystem::AddHandler(new wxZipFSHandler);
|
||||||
|
|
||||||
|
// Use the system language for dialogs that are displayed before
|
||||||
|
// the user selected language is available from preferences.
|
||||||
|
mLocale = NULL;
|
||||||
|
InitLang(GetSystemLanguageCode());
|
||||||
|
|
||||||
|
// Check for another running instance. This must be done before
|
||||||
|
// any activities that may modify the same resources of the other
|
||||||
|
// instance, like initializing preferences.
|
||||||
|
if (!CreateSingleInstanceChecker()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we know we're the only instance running, so we're safe to
|
||||||
|
// initialize preferences
|
||||||
InitPreferences();
|
InitPreferences();
|
||||||
|
|
||||||
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
|
#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) && !defined(__CYGWIN__)
|
||||||
@@ -1161,16 +1168,13 @@ bool AudacityApp::OnInit()
|
|||||||
wxGetUserId().c_str());
|
wxGetUserId().c_str());
|
||||||
#endif //__WXMAC__
|
#endif //__WXMAC__
|
||||||
|
|
||||||
// Locale
|
// Reset the language now that translation paths and preferences are available
|
||||||
// wxWidgets 2.3 has a much nicer wxLocale API. We can make this code much
|
|
||||||
// better once we move to wx 2.3/2.4.
|
|
||||||
|
|
||||||
wxString lang = gPrefs->Read(wxT("/Locale/Language"), wxT(""));
|
wxString lang = gPrefs->Read(wxT("/Locale/Language"), wxT(""));
|
||||||
|
|
||||||
if (lang == wxT(""))
|
if (lang == wxT(""))
|
||||||
lang = GetSystemLanguageCode();
|
lang = GetSystemLanguageCode();
|
||||||
|
|
||||||
mLocale = NULL;
|
|
||||||
InitLang( lang );
|
InitLang( lang );
|
||||||
|
|
||||||
// Init DirManager, which initializes the temp directory
|
// Init DirManager, which initializes the temp directory
|
||||||
@@ -1515,52 +1519,44 @@ bool AudacityApp::InitTempDir()
|
|||||||
{
|
{
|
||||||
// We need to find a temp directory location.
|
// We need to find a temp directory location.
|
||||||
|
|
||||||
wxString tempFromPrefs = gPrefs->Read(wxT("/Directories/TempDir"), wxT(""));
|
wxFileName temp;
|
||||||
wxString tempDefaultLoc = wxGetApp().defaultTempDir;
|
wxArrayString paths;
|
||||||
|
paths.Add(gPrefs->Read(wxT("/Directories/TempDir"), wxEmptyString));
|
||||||
|
paths.Add(defaultTempDir);
|
||||||
|
|
||||||
wxString temp = wxT("");
|
for (size_t i = 0, cnt = paths.GetCount(); i < cnt; i++)
|
||||||
|
{
|
||||||
#ifdef __WXGTK__
|
temp.SetPath(paths[i]);
|
||||||
if (tempFromPrefs.Length() > 0 && tempFromPrefs[0] != wxT('/'))
|
temp.AppendDir(wxGetUserId() + wxT("-temp-dir"));
|
||||||
tempFromPrefs = wxT("");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Stop wxWidgets from printing its own error messages
|
|
||||||
|
|
||||||
wxLogNull logNo;
|
|
||||||
|
|
||||||
// Try temp dir that was stored in prefs first
|
|
||||||
|
|
||||||
if (tempFromPrefs != wxT("")) {
|
|
||||||
if (wxDirExists(tempFromPrefs))
|
|
||||||
temp = tempFromPrefs;
|
|
||||||
else if (wxMkdir(tempFromPrefs, 0755))
|
|
||||||
temp = tempFromPrefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If that didn't work, try the default location
|
|
||||||
|
|
||||||
if (temp==wxT("") && tempDefaultLoc != wxT("")) {
|
|
||||||
if (wxDirExists(tempDefaultLoc))
|
|
||||||
temp = tempDefaultLoc;
|
|
||||||
else if (wxMkdir(tempDefaultLoc, 0755))
|
|
||||||
temp = tempDefaultLoc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (temp.IsOk() && temp.IsAbsolute())
|
||||||
|
{
|
||||||
|
if (temp.DirExists() || temp.Mkdir(0755, wxPATH_MKDIR_FULL))
|
||||||
|
{
|
||||||
|
#ifdef __UNIX__
|
||||||
// Check temp directory ownership on *nix systems only
|
// Check temp directory ownership on *nix systems only
|
||||||
#ifdef __UNIX__
|
wxStructStat stats;
|
||||||
struct stat tempStatBuf;
|
if (wxLstat(temp.GetFullPath(), &stats) != 0 || stats.st_uid != geteuid())
|
||||||
if ( lstat(temp.mb_str(), &tempStatBuf) != 0 ) {
|
{
|
||||||
temp.clear();
|
temp.Clear();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if ( geteuid() != tempStatBuf.st_uid ) {
|
|
||||||
temp.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (temp == wxT("")) {
|
// The permissions don't always seem to be set on
|
||||||
|
// some platforms. Hopefully this fixes it...
|
||||||
|
chmod(OSFILENAME(temp.GetFullPath()), 0755);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gPrefs->Write(wxT("/Directories/TempDir"), paths[i]) && gPrefs->Flush();
|
||||||
|
DirManager::SetTempDir(temp.GetFullPath());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
temp.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!temp.IsOk())
|
||||||
|
{
|
||||||
// Failed
|
// Failed
|
||||||
wxMessageBox(_("Audacity could not find a place to store temporary files.\nPlease enter an appropriate directory in the preferences dialog."));
|
wxMessageBox(_("Audacity could not find a place to store temporary files.\nPlease enter an appropriate directory in the preferences dialog."));
|
||||||
|
|
||||||
@@ -1572,44 +1568,25 @@ bool AudacityApp::InitTempDir()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The permissions don't always seem to be set on
|
return true;
|
||||||
// some platforms. Hopefully this fixes it...
|
|
||||||
#ifdef __UNIX__
|
|
||||||
chmod(OSFILENAME(temp), 0755);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool bSuccess = gPrefs->Write(wxT("/Directories/TempDir"), temp) && gPrefs->Flush();
|
|
||||||
DirManager::SetTempDir(temp);
|
|
||||||
|
|
||||||
// Make sure the temp dir isn't locked by another process.
|
|
||||||
if (!CreateSingleInstanceChecker(temp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return bSuccess;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return true if there are no other instances of Audacity running,
|
// Return true if there are no other instances of Audacity running,
|
||||||
// false otherwise.
|
// false otherwise.
|
||||||
//
|
bool AudacityApp::CreateSingleInstanceChecker()
|
||||||
// Use "dir" for creating lockfiles (on OS X and Unix).
|
|
||||||
|
|
||||||
bool AudacityApp::CreateSingleInstanceChecker(wxString dir)
|
|
||||||
{
|
{
|
||||||
wxLogNull dontLog;
|
wxString name = wxString(wxT(".")) + IPC_APPL;
|
||||||
|
|
||||||
wxString name = wxString::Format(wxT("audacity-lock-%s"), wxGetUserId().c_str());
|
|
||||||
mChecker = new wxSingleInstanceChecker();
|
mChecker = new wxSingleInstanceChecker();
|
||||||
|
|
||||||
#if defined(__WXMSW__) || defined(__WXGTK__)
|
|
||||||
wxString appl = IPC_APPL;
|
wxString appl = IPC_APPL;
|
||||||
#if defined(__WXGTK__)
|
|
||||||
appl.Printf(wxT("%s/%s.sock"), dir.c_str(), IPC_APPL);
|
#if defined(__WXGTK__) || defined(__WXMAC__)
|
||||||
#endif
|
appl = wxGetHomeDir() + wxT("/") + name + wxT(".sock");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wxString runningTwoCopiesStr = _("Running two copies of Audacity simultaneously may cause\ndata loss or cause your system to crash.\n\n");
|
wxString runningTwoCopiesStr = _("Running two copies of Audacity simultaneously may cause\ndata loss or cause your system to crash.\n\n");
|
||||||
|
|
||||||
if (!mChecker->Create(name, dir)) {
|
if (!mChecker->Create(name + wxT(".lock"), wxGetHomeDir())) {
|
||||||
// Error initializing the wxSingleInstanceChecker. We don't know
|
// Error initializing the wxSingleInstanceChecker. We don't know
|
||||||
// whether there is another instance running or not.
|
// whether there is another instance running or not.
|
||||||
|
|
||||||
@@ -1627,7 +1604,6 @@ bool AudacityApp::CreateSingleInstanceChecker(wxString dir)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( mChecker->IsAnotherRunning() ) {
|
else if ( mChecker->IsAnotherRunning() ) {
|
||||||
#if defined(__WXMSW__) || defined(__WXGTK__)
|
|
||||||
// Get the 1st argument (filename) if there is one.
|
// Get the 1st argument (filename) if there is one.
|
||||||
wxString cmd;
|
wxString cmd;
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
@@ -1642,10 +1618,10 @@ bool AudacityApp::CreateSingleInstanceChecker(wxString dir)
|
|||||||
wxClient client;
|
wxClient client;
|
||||||
wxConnectionBase *conn;
|
wxConnectionBase *conn;
|
||||||
|
|
||||||
// We try up to 10 times since there's a small window
|
// We try up to 50 times since there's a small window
|
||||||
// where the DDE server on Windows may not have been fully
|
// where the DDE server on Windows may not have been fully
|
||||||
// initialized.
|
// initialized.
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 50; i++) {
|
||||||
conn = client.MakeConnection(wxEmptyString,
|
conn = client.MakeConnection(wxEmptyString,
|
||||||
appl,
|
appl,
|
||||||
IPC_TOPIC);
|
IPC_TOPIC);
|
||||||
@@ -1663,7 +1639,7 @@ bool AudacityApp::CreateSingleInstanceChecker(wxString dir)
|
|||||||
}
|
}
|
||||||
wxMilliSleep(100);
|
wxMilliSleep(100);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
// There is another copy of Audacity running. Force quit.
|
// There is another copy of Audacity running. Force quit.
|
||||||
|
|
||||||
wxString prompt =
|
wxString prompt =
|
||||||
@@ -1676,10 +1652,8 @@ bool AudacityApp::CreateSingleInstanceChecker(wxString dir)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__WXMSW__) || defined(__WXGTK__)
|
|
||||||
// Create the DDE server
|
// Create the DDE server
|
||||||
mIPCServ = new IPCServ(appl);
|
mIPCServ = new IPCServ(appl);
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1843,9 +1817,7 @@ int AudacityApp::OnExit()
|
|||||||
Dispatch();
|
Dispatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__WXMSW__) || defined(__WXGTK__)
|
|
||||||
delete mIPCServ;
|
delete mIPCServ;
|
||||||
#endif
|
|
||||||
|
|
||||||
Importer::Get().Terminate();
|
Importer::Get().Terminate();
|
||||||
|
|
||||||
|
|||||||
@@ -220,16 +220,15 @@ class AudacityApp:public wxApp {
|
|||||||
void DeInitCommandHandler();
|
void DeInitCommandHandler();
|
||||||
|
|
||||||
bool InitTempDir();
|
bool InitTempDir();
|
||||||
bool CreateSingleInstanceChecker(wxString dir);
|
bool CreateSingleInstanceChecker();
|
||||||
|
|
||||||
/* utility method for printing the command line help message */
|
/* utility method for printing the command line help message */
|
||||||
void PrintCommandLineHelp(void);
|
void PrintCommandLineHelp(void);
|
||||||
|
|
||||||
bool mWindowRectAlreadySaved;
|
bool mWindowRectAlreadySaved;
|
||||||
|
|
||||||
#if defined(__WXMSW__) || defined(__WXGTK__)
|
|
||||||
IPCServ *mIPCServ;
|
IPCServ *mIPCServ;
|
||||||
#endif
|
|
||||||
public:
|
public:
|
||||||
DECLARE_EVENT_TABLE()
|
DECLARE_EVENT_TABLE()
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user