/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-7 by Raw Material Software ltd. ------------------------------------------------------------------------------ JUCE can be redistributed and/or modified under the terms of the GNU General Public License, as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JUCE; if not, visit www.gnu.org/licenses or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------------ If you'd like to release a closed-source product which uses JUCE, commercial licenses are also available: visit www.rawmaterialsoftware.com/juce for more information. ============================================================================== */ #include "../../juce_core/basics/juce_StandardHeader.h" #if JUCE_MSVC #pragma warning (push) #pragma warning (disable: 4245 4514 4100) #include #pragma warning (pop) #endif BEGIN_JUCE_NAMESPACE #include "juce_Application.h" #include "juce_DeletedAtShutdown.h" #include "../events/juce_MessageManager.h" #include "../gui/graphics/contexts/juce_Graphics.h" #include "../gui/components/windows/juce_AlertWindow.h" #include "../gui/components/buttons/juce_TextButton.h" #include "../gui/components/lookandfeel/juce_LookAndFeel.h" #include "../../juce_core/basics/juce_Time.h" #include "../../juce_core/basics/juce_Initialisation.h" #include "../../juce_core/threads/juce_Process.h" #include "../../juce_core/threads/juce_InterProcessLock.h" void juce_setCurrentExecutableFileName (const String& filename) throw(); void juce_setCurrentThreadName (const String& name) throw(); static JUCEApplication* appInstance = 0; //============================================================================== JUCEApplication::JUCEApplication() : stillInitialising (true) { } JUCEApplication::~JUCEApplication() { } JUCEApplication* JUCEApplication::getInstance() { return appInstance; } bool JUCEApplication::isInitialising() const { return stillInitialising; } //============================================================================== const String JUCEApplication::getApplicationVersion() { return String::empty; } bool JUCEApplication::moreThanOneInstanceAllowed() { return true; } void JUCEApplication::anotherInstanceStarted (const String&) { } void JUCEApplication::systemRequestedQuit() { quit(); } void JUCEApplication::quit (const bool useMaximumForce) { MessageManager::getInstance()->postQuitMessage (useMaximumForce); } //============================================================================== void JUCEApplication::unhandledException (const std::exception*, const String&, const int) { jassertfalse } void JUCEApplication::sendUnhandledException (const std::exception* const e, const char* const sourceFile, const int lineNumber) { if (appInstance != 0) appInstance->unhandledException (e, sourceFile, lineNumber); } //============================================================================== ApplicationCommandTarget* JUCEApplication::getNextCommandTarget() { return 0; } void JUCEApplication::getAllCommands (Array & commands) { commands.add (StandardApplicationCommandIDs::quit); } void JUCEApplication::getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result) { if (commandID == StandardApplicationCommandIDs::quit) { result.setInfo ("Quit", "Quits the application", "Application", 0); result.defaultKeypresses.add (KeyPress (T('q'), ModifierKeys::commandModifier, 0)); } } bool JUCEApplication::perform (const InvocationInfo& info) { if (info.commandID == StandardApplicationCommandIDs::quit) { systemRequestedQuit(); return true; } return false; } //============================================================================== // used as a listener object later on.. class NewAppListener : public ActionListener { public: void actionListenerCallback (const String& message) { if (message.startsWith (appInstance->getApplicationName() + T("/"))) { appInstance->anotherInstanceStarted (message.fromFirstOccurrenceOf (T("/"), false, false)); } } }; int JUCEApplication::main (String& commandLine, JUCEApplication* const app) { jassert (appInstance == 0); appInstance = app; bool useForce = true; initialiseJuce_GUI(); InterProcessLock* appLock = 0; if (! app->moreThanOneInstanceAllowed()) { appLock = new InterProcessLock ("juceAppLock_" + app->getApplicationName()); if (! appLock->enter(0)) { MessageManager::broadcastMessage (app->getApplicationName() + T("/") + commandLine); delete appInstance; appInstance = 0; commandLine = String::empty; DBG ("Another instance is running - quitting..."); return 0; } } JUCE_TRY { juce_setCurrentThreadName ("Juce Message Thread"); // let the app do its setting-up.. app->initialise (commandLine.trim()); commandLine = String::empty; // register for broadcast new app messages NewAppListener* const newAppListener = new NewAppListener(); MessageManager::getInstance()->registerBroadcastListener (newAppListener); app->stillInitialising = false; // now loop until a quit message is received.. useForce = MessageManager::getInstance()->runDispatchLoop(); delete newAppListener; if (appLock != 0) { appLock->exit(); delete appLock; } } #if JUCE_CATCH_UNHANDLED_EXCEPTIONS catch (const std::exception& e) { app->unhandledException (&e, __FILE__, __LINE__); } catch (...) { app->unhandledException (0, __FILE__, __LINE__); } #endif shutdownAppAndClearUp (useForce); return 0; } void JUCEApplication::shutdownAppAndClearUp (bool useMaximumForce) { jassert (appInstance != 0); JUCEApplication* const app = appInstance; static bool reentrancyCheck = false; if (! reentrancyCheck) { reentrancyCheck = true; JUCE_TRY { // give the app a chance to clean up.. app->shutdown(); } #if JUCE_CATCH_UNHANDLED_EXCEPTIONS catch (const std::exception& e) { app->unhandledException (&e, __FILE__, __LINE__); } catch (...) { app->unhandledException (0, __FILE__, __LINE__); } #endif JUCE_TRY { shutdownJuce_GUI(); appInstance = 0; delete app; } JUCE_CATCH_ALL_ASSERT if (useMaximumForce) { Process::terminate(); } reentrancyCheck = false; } } int JUCEApplication::main (int argc, char* argv[], JUCEApplication* const newApp) { juce_setCurrentExecutableFileName (argv[0]); String cmd; for (int i = 1; i < argc; ++i) cmd << argv[i] << T(' '); return JUCEApplication::main (cmd, newApp); } //============================================================================== static bool juceInitialisedGUI = false; void JUCE_PUBLIC_FUNCTION initialiseJuce_GUI() { if (! juceInitialisedGUI) { juceInitialisedGUI = true; initialiseJuce_NonGUI(); MessageManager::getInstance(); Font::initialiseDefaultFontNames(); LookAndFeel::setDefaultLookAndFeel (0); #if JUCE_WIN32 && JUCE_DEBUG // This section is just for catching people who mess up their project settings and // turn RTTI off.. try { TextButton tb (String::empty); Component* c = &tb; // Got an exception here? Then TURN ON RTTI in your compiler settings!! c = dynamic_cast (c); } catch (...) { // Ended up here? If so, TURN ON RTTI in your compiler settings!! And if you // got as far as this catch statement, then why haven't you got exception catching // turned on in the debugger??? jassertfalse } #endif } } void JUCE_PUBLIC_FUNCTION shutdownJuce_GUI() { if (juceInitialisedGUI) { DeletedAtShutdown::deleteAll(); LookAndFeel::clearDefaultLookAndFeel(); shutdownJuce_NonGUI(); juceInitialisedGUI = false; } } END_JUCE_NAMESPACE