From 8a006e589c2ea83977e1e923c0ba14f9803a1e13 Mon Sep 17 00:00:00 2001 From: jules Date: Wed, 25 Jul 2012 07:53:28 +0100 Subject: [PATCH] Cleaned up some application startup code. --- .../Source/Application/jucer_Application.h | 18 +-- .../Source/Application/jucer_CommandLine.cpp | 17 +++ .../juce_core/threads/juce_InterProcessLock.h | 22 ++-- .../application/juce_Application.cpp | 107 ++++++++++++------ .../application/juce_Application.h | 10 +- .../native/juce_mac_NSViewComponentPeer.mm | 4 +- 6 files changed, 118 insertions(+), 60 deletions(-) diff --git a/extras/Introjucer/Source/Application/jucer_Application.h b/extras/Introjucer/Source/Application/jucer_Application.h index 2cc0a45f5b..f9328a3dd8 100644 --- a/extras/Introjucer/Source/Application/jucer_Application.h +++ b/extras/Introjucer/Source/Application/jucer_Application.h @@ -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) diff --git a/extras/Introjucer/Source/Application/jucer_CommandLine.cpp b/extras/Introjucer/Source/Application/jucer_CommandLine.cpp index 774c392b29..60d7beb8d5 100644 --- a/extras/Introjucer/Source/Application/jucer_CommandLine.cpp +++ b/extras/Introjucer/Source/Application/jucer_CommandLine.cpp @@ -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 diff --git a/modules/juce_core/threads/juce_InterProcessLock.h b/modules/juce_core/threads/juce_InterProcessLock.h index 33e8f2f3ae..8381b65f42 100644 --- a/modules/juce_core/threads/juce_InterProcessLock.h +++ b/modules/juce_core/threads/juce_InterProcessLock.h @@ -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); diff --git a/modules/juce_gui_basics/application/juce_Application.cpp b/modules/juce_gui_basics/application/juce_Application.cpp index e01bd40a11..cf6e531284 100644 --- a/modules/juce_gui_basics/application/juce_Application.cpp +++ b/modules/juce_gui_basics/application/juce_Application.cpp @@ -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 - - #if ! (JUCE_IOS || JUCE_ANDROID) - broadcastCallback = new AppBroadcastCallback(); - #endif - stillInitialising = false; + + 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 + } + 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(); } diff --git a/modules/juce_gui_basics/application/juce_Application.h b/modules/juce_gui_basics/application/juce_Application.h index d9fa216c64..039f7e3e56 100644 --- a/modules/juce_gui_basics/application/juce_Application.h +++ b/modules/juce_gui_basics/application/juce_Application.h @@ -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 appLock; - ScopedPointer broadcastCallback; + struct MultipleInstanceHandler; + friend struct MultipleInstanceHandler; + friend class ScopedPointer; + ScopedPointer multipleInstanceHandler; + int appReturnValue; bool stillInitialising; diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index eba34376e0..b012254472 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -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 }