| @@ -45,10 +45,7 @@ public: | |||
| void initialise (const String& commandLine) | |||
| { | |||
| LookAndFeel::setDefaultLookAndFeel (&lookAndFeel); | |||
| settings = new StoredSettings(); | |||
| icons = new Icons(); | |||
| settings->initialise(); | |||
| if (commandLine.isNotEmpty()) | |||
| @@ -63,6 +60,15 @@ public: | |||
| } | |||
| } | |||
| if (sendCommandLineToPreexistingInstance()) | |||
| { | |||
| DBG ("Another instance is running - quitting..."); | |||
| quit(); | |||
| return; | |||
| } | |||
| icons = new Icons(); | |||
| commandManager = new ApplicationCommandManager(); | |||
| commandManager->registerAllCommandsForTarget (this); | |||
| @@ -131,11 +137,7 @@ public: | |||
| bool moreThanOneInstanceAllowed() | |||
| { | |||
| #ifndef JUCE_LINUX | |||
| return false; | |||
| #else | |||
| return true; //xxx should be false but doesn't work on linux.. | |||
| #endif | |||
| return true; // this is handled manually in initialise() | |||
| } | |||
| void anotherInstanceStarted (const String& commandLine) | |||
| @@ -31,6 +31,13 @@ | |||
| //============================================================================== | |||
| namespace | |||
| { | |||
| void hideDockIcon() | |||
| { | |||
| #if JUCE_MAC | |||
| Process::setDockIconVisible (false); | |||
| #endif | |||
| } | |||
| File getFile (const String& filename) | |||
| { | |||
| return File::getCurrentWorkingDirectory().getChildFile (filename.unquoted()); | |||
| @@ -53,6 +60,8 @@ namespace | |||
| */ | |||
| int resaveProject (const StringArray& args, bool justSaveResources) | |||
| { | |||
| hideDockIcon(); | |||
| if (! checkArgumentCount (args, 2)) | |||
| return 1; | |||
| @@ -145,6 +154,8 @@ namespace | |||
| int buildModules (const StringArray& args, const bool buildAllWithIndex) | |||
| { | |||
| hideDockIcon(); | |||
| if (! checkArgumentCount (args, 3)) | |||
| return 1; | |||
| @@ -200,6 +211,8 @@ namespace | |||
| int listModules() | |||
| { | |||
| hideDockIcon(); | |||
| std::cout << "Downloading list of available modules..." << std::endl; | |||
| ModuleList list; | |||
| list.loadFromWebsite(); | |||
| @@ -216,6 +229,8 @@ namespace | |||
| int showStatus (const StringArray& args) | |||
| { | |||
| hideDockIcon(); | |||
| if (! checkArgumentCount (args, 2)) | |||
| return 1; | |||
| @@ -256,6 +271,8 @@ namespace | |||
| //============================================================================== | |||
| int showHelp() | |||
| { | |||
| hideDockIcon(); | |||
| std::cout << "The Introjucer!" << std::endl | |||
| << std::endl | |||
| << "Usage: " << std::endl | |||
| @@ -41,13 +41,11 @@ class JUCE_API InterProcessLock | |||
| public: | |||
| //============================================================================== | |||
| /** Creates a lock object. | |||
| @param name a name that processes will use to identify this lock object | |||
| @param name a name that processes will use to identify this lock object | |||
| */ | |||
| explicit InterProcessLock (const String& name); | |||
| /** Destructor. | |||
| This will also release the lock if it's currently held by this process. | |||
| */ | |||
| ~InterProcessLock(); | |||
| @@ -55,17 +53,15 @@ public: | |||
| //============================================================================== | |||
| /** Attempts to lock the critical section. | |||
| @param timeOutMillisecs how many milliseconds to wait if the lock | |||
| is already held by another process - a value of | |||
| 0 will return immediately, negative values will wait | |||
| forever | |||
| @param timeOutMillisecs how many milliseconds to wait if the lock is already | |||
| held by another process - a value of 0 will return | |||
| immediately, negative values will wait forever | |||
| @returns true if the lock could be gained within the timeout period, or | |||
| false if the timeout expired. | |||
| */ | |||
| bool enter (int timeOutMillisecs = -1); | |||
| /** Releases the lock if it's currently held by this process. | |||
| */ | |||
| /** Releases the lock if it's currently held by this process. */ | |||
| void exit(); | |||
| //============================================================================== | |||
| @@ -94,7 +90,7 @@ public: | |||
| otherwise there are no guarantees what will happen! Best just to use it | |||
| as a local stack object, rather than creating one with the new() operator. | |||
| */ | |||
| explicit ScopedLockType (InterProcessLock& lock) : lock_ (lock) { lockWasSuccessful = lock.enter(); } | |||
| explicit ScopedLockType (InterProcessLock& lock) : ipLock (lock) { lockWasSuccessful = lock.enter(); } | |||
| /** Destructor. | |||
| @@ -103,14 +99,14 @@ public: | |||
| Make sure this object is created and deleted by the same thread, | |||
| otherwise there are no guarantees what will happen! | |||
| */ | |||
| inline ~ScopedLockType() { lock_.exit(); } | |||
| inline ~ScopedLockType() { ipLock.exit(); } | |||
| /** Returns true if the InterProcessLock was successfully locked. */ | |||
| bool isLocked() const noexcept { return lockWasSuccessful; } | |||
| bool isLocked() const noexcept { return lockWasSuccessful; } | |||
| private: | |||
| //============================================================================== | |||
| InterProcessLock& lock_; | |||
| InterProcessLock& ipLock; | |||
| bool lockWasSuccessful; | |||
| JUCE_DECLARE_NON_COPYABLE (ScopedLockType); | |||
| @@ -27,21 +27,54 @@ | |||
| extern void juce_initialiseMacMainMenu(); | |||
| #endif | |||
| #if ! (JUCE_IOS || JUCE_ANDROID) | |||
| #define JUCE_HANDLE_MULTIPLE_INSTANCES 1 | |||
| #endif | |||
| //============================================================================== | |||
| class AppBroadcastCallback : public ActionListener | |||
| #if JUCE_HANDLE_MULTIPLE_INSTANCES | |||
| struct JUCEApplication::MultipleInstanceHandler : public ActionListener | |||
| { | |||
| public: | |||
| AppBroadcastCallback() { MessageManager::getInstance()->registerBroadcastListener (this); } | |||
| ~AppBroadcastCallback() { MessageManager::getInstance()->deregisterBroadcastListener (this); } | |||
| MultipleInstanceHandler (const String& appName) | |||
| : appLock ("juceAppLock_" + appName) | |||
| { | |||
| } | |||
| bool sendCommandLineToPreexistingInstance() | |||
| { | |||
| if (appLock.enter (0)) | |||
| return false; | |||
| JUCEApplication* const app = JUCEApplication::getInstance(); | |||
| jassert (app != nullptr); | |||
| MessageManager::broadcastMessage (app->getApplicationName() | |||
| + "/" + app->getCommandLineParameters()); | |||
| return true; | |||
| } | |||
| void actionListenerCallback (const String& message) | |||
| { | |||
| JUCEApplication* const app = JUCEApplication::getInstance(); | |||
| if (app != 0 && message.startsWith (app->getApplicationName() + "/")) | |||
| app->anotherInstanceStarted (message.substring (app->getApplicationName().length() + 1)); | |||
| if (app != nullptr) | |||
| { | |||
| const String appName (app->getApplicationName()); | |||
| if (message.startsWith (appName + "/")) | |||
| app->anotherInstanceStarted (message.substring (appName.length() + 1)); | |||
| } | |||
| } | |||
| private: | |||
| InterProcessLock appLock; | |||
| JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultipleInstanceHandler); | |||
| }; | |||
| #else | |||
| struct JUCEApplication::MultipleInstanceHandler {}; | |||
| #endif | |||
| //============================================================================== | |||
| JUCEApplication::JUCEApplication() | |||
| @@ -52,11 +85,6 @@ JUCEApplication::JUCEApplication() | |||
| JUCEApplication::~JUCEApplication() | |||
| { | |||
| if (appLock != nullptr) | |||
| { | |||
| appLock->exit(); | |||
| appLock = nullptr; | |||
| } | |||
| } | |||
| //============================================================================== | |||
| @@ -82,9 +110,7 @@ void JUCEApplication::setApplicationReturnValue (const int newReturnValue) noexc | |||
| } | |||
| //============================================================================== | |||
| void JUCEApplication::unhandledException (const std::exception*, | |||
| const String&, | |||
| const int) | |||
| void JUCEApplication::unhandledException (const std::exception*, const String&, int) | |||
| { | |||
| jassertfalse; | |||
| } | |||
| @@ -132,39 +158,44 @@ bool JUCEApplication::perform (const InvocationInfo& info) | |||
| return false; | |||
| } | |||
| #if JUCE_HANDLE_MULTIPLE_INSTANCES | |||
| bool JUCEApplication::sendCommandLineToPreexistingInstance() | |||
| { | |||
| jassert (multipleInstanceHandler == nullptr); // this must only be called once! | |||
| multipleInstanceHandler = new MultipleInstanceHandler (getApplicationName()); | |||
| return multipleInstanceHandler->sendCommandLineToPreexistingInstance(); | |||
| } | |||
| #endif | |||
| //============================================================================== | |||
| bool JUCEApplication::initialiseApp() | |||
| { | |||
| #if ! (JUCE_IOS || JUCE_ANDROID) | |||
| jassert (appLock == nullptr); // initialiseApp must only be called once! | |||
| if (! moreThanOneInstanceAllowed()) | |||
| #if JUCE_HANDLE_MULTIPLE_INSTANCES | |||
| if ((! moreThanOneInstanceAllowed()) && sendCommandLineToPreexistingInstance()) | |||
| { | |||
| appLock = new InterProcessLock ("juceAppLock_" + getApplicationName()); | |||
| if (! appLock->enter(0)) | |||
| { | |||
| appLock = nullptr; | |||
| MessageManager::broadcastMessage (getApplicationName() + "/" + getCommandLineParameters()); | |||
| DBG ("Another instance is running - quitting..."); | |||
| return false; | |||
| } | |||
| DBG ("Another instance is running - quitting..."); | |||
| return false; | |||
| } | |||
| #endif | |||
| // let the app do its setting-up.. | |||
| initialise (getCommandLineParameters()); | |||
| #if JUCE_MAC | |||
| juce_initialiseMacMainMenu(); // needs to be called after the app object has created, to get its name | |||
| #endif | |||
| stillInitialising = false; | |||
| #if ! (JUCE_IOS || JUCE_ANDROID) | |||
| broadcastCallback = new AppBroadcastCallback(); | |||
| #endif | |||
| if (! MessageManager::getInstance()->hasStopMessageBeenSent()) | |||
| { | |||
| #if JUCE_MAC | |||
| juce_initialiseMacMainMenu(); // (needs to get the app's name) | |||
| #endif | |||
| #if JUCE_HANDLE_MULTIPLE_INSTANCES | |||
| if (multipleInstanceHandler != nullptr) | |||
| MessageManager::getInstance()->registerBroadcastListener (multipleInstanceHandler); | |||
| #endif | |||
| } | |||
| stillInitialising = false; | |||
| return true; | |||
| } | |||
| @@ -172,7 +203,10 @@ int JUCEApplication::shutdownApp() | |||
| { | |||
| jassert (JUCEApplicationBase::getInstance() == this); | |||
| broadcastCallback = nullptr; | |||
| #if JUCE_HANDLE_MULTIPLE_INSTANCES | |||
| if (multipleInstanceHandler != nullptr) | |||
| MessageManager::getInstance()->deregisterBroadcastListener (multipleInstanceHandler); | |||
| #endif | |||
| JUCE_TRY | |||
| { | |||
| @@ -181,6 +215,7 @@ int JUCEApplication::shutdownApp() | |||
| } | |||
| JUCE_CATCH_EXCEPTION | |||
| multipleInstanceHandler = nullptr; | |||
| return getApplicationReturnValue(); | |||
| } | |||
| @@ -246,12 +246,18 @@ public: | |||
| static void sendUnhandledException (const std::exception*, const char* sourceFile, int lineNumber); | |||
| bool initialiseApp(); | |||
| int shutdownApp(); | |||
| protected: | |||
| bool sendCommandLineToPreexistingInstance(); | |||
| #endif | |||
| private: | |||
| //============================================================================== | |||
| ScopedPointer<InterProcessLock> appLock; | |||
| ScopedPointer<ActionListener> broadcastCallback; | |||
| struct MultipleInstanceHandler; | |||
| friend struct MultipleInstanceHandler; | |||
| friend class ScopedPointer<MultipleInstanceHandler>; | |||
| ScopedPointer<MultipleInstanceHandler> multipleInstanceHandler; | |||
| int appReturnValue; | |||
| bool stillInitialising; | |||
| @@ -103,7 +103,6 @@ public: | |||
| styleMask: getNSWindowStyleMask (windowStyleFlags) | |||
| backing: NSBackingStoreBuffered | |||
| defer: YES]; | |||
| setOwner (window, this); | |||
| [window orderOut: nil]; | |||
| #if defined (MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 | |||
| @@ -132,6 +131,9 @@ public: | |||
| #if defined (MAC_OS_X_VERSION_10_7) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7) | |||
| if ((windowStyleFlags & (windowHasMaximiseButton | windowHasTitleBar)) == (windowHasMaximiseButton | windowHasTitleBar)) | |||
| [window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary]; | |||
| if ([window respondsToSelector: @selector (setRestorable:)]) | |||
| [window setRestorable: NO]; | |||
| #endif | |||
| } | |||